我们有一个表格,其形式为:
ID,Value1,Value2,Value3
1,2,3,4
我们需要将其转化为。
ID,Name,Value
1,'Value1',2
1,'Value2',3
1,'Value3',4
在一个 SELECT 语句中(即没有 UNION)有没有一种聪明的方法?列名 Value1、Value2 和 Value3 是固定不变的。
数据库是oracle 9i。
试一试union
。
select ID, 'Value1' as Name, Value1 as Value from table_name union all
select ID, 'Value2', Value2 as Value from table_name union all
select ID, 'Value3', Value3 as Value from table_name
order by ID, Name
usingunion all
意味着服务器不会执行 a distinct
(这在操作中是隐含的union
)。它不应该对数据产生任何影响(因为您的 ID 应该完全不同),但它可能会加快速度。
这适用于 Oracle 10g:
select id, 'Value' || n as name,
case n when 1 then value1 when 2 then value2 when 3 then value3 end as value
from (select rownum n
from (select 1 from dual connect by level <= 3)) ofs, t
我认为 Oracle 9i 有递归查询?无论如何,我很确定它有 CASE 支持,所以即使它没有递归查询,您也可以执行“(select 1 from dual union all select 2 from dual union all select 3 from dual) ofs”代替。对 Oracle 来说,滥用递归查询更为普遍。(不过,使用联合生成行可以移植到其他数据库)
你可以这样做,但它并不漂亮:
SELECT id,'Value 1' AS name,value1 AS value FROM mytable
UNION
SELECT id,'Value 2' AS name,value2 AS value FROM mytable
UNION
SELECT id,'Value 3' AS name,value3 AS value FROM mytable
联合三个 select 语句应该可以解决问题:
SELECT ID, 'Value1', Value1 AS Value
FROM TABLE
UNION
SELECT ID, 'Value2', Value2 AS Value
FROM TABLE
UNION
SELECT ID, 'Value3', Value3 AS Value
FROM TABLE
如果您使用的是 SQL Server 2005+,那么您可以使用 UNPIVOT
CREATE TABLE #tmp ( ID int, Value1 int, Value2 int, Value3 int)
INSERT INTO #tmp (ID, Value1, Value2, Value3) VALUES (1, 2, 3, 4)
SELECT
*
FROM
#tmp
SELECT
*
FROM
#tmp
UNPIVOT
(
[Value] FOR [Name] IN (Value1, Value2, Value3)
) uPIVOT
DROP TABLE #tmp
正如其他人所建议的那样,UNION ALL 可能是您在 SQL 中的最佳选择。您可能还需要考虑在前端处理此问题,具体取决于您的具体要求。
Oracle 的 CTE 语法可能不同(我在 Teradata 中运行它),但我只使用 CTE 提供测试数据,即 1 2 3 和 4。您可以使用临时表。实际的 select 语句是普通的普通 SQL,它适用于任何关系数据库。
对于 Sql Server,考虑 UNPIVOT 作为 UNION 的替代方案:
SELECT id, value, colname
FROM #temp t
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X
这也将返回列名。我不确定 X 的用途,但你不能忽略它。
试试这个:
CTE 创建一个包含 4 个值的临时表。您可以在任何数据库中按原样运行它。
with TEST_CTE (ID) as
(select * from (select '1' as a) as aa union all
select * from (select '2' as b) as bb union all
select * from (select '3' as c) as cc union all
select * from (select '4' as d) as dd )
select a.ID, 'Value'|| a.ID, b.ID
from TEST_CTE a, TEST_CTE b
where b.ID = (select min(c.ID) from TEST_CTE c where c.ID > a.ID)
这是结果集:
1 Value1 2
2 Value2 3
3 Value3 4
享受!
一些事后的想法。
^^^ CTE 语法在 Oracle 中可能不同。我只能在 Teradata 中运行它。您可以将其替换为临时表或修复语法以使其与 Oracle 兼容。select 语句是普通的普通 SQL,适用于任何数据库。
^^^ 还有一点要注意。如果 ID 字段是数字,您可能需要将其转换为 CHAR 以便将其与“值”连接起来。