单个SQL SELECT从一个表行返回多个行

时间:2009-05-20 13:23:40

标签: sql oracle select plsql oracle9i

我们有一个表格形式:

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。

9 个答案:

答案 0 :(得分:9)

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

使用union all意味着服务器不会执行distinctunion操作中隐含的)。它不应该对数据产生任何影响(因为你的ID应该很可能是不同的),但它可能会加快一点。

答案 1 :(得分:4)

这适用于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支持,所以即使它没有递归查询,你也可以做“(从双联合中选择1,所有选择2来自双联盟,所有选择3来自双重)”。对于Oracle来说,滥用递归查询更为通用。 (但是,使用联合生成行可以移植到其他数据库)

答案 2 :(得分:2)

你可以这样做,但它并不漂亮:

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

答案 3 :(得分:2)

联合三个选择语句应该可以解决问题:

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

答案 4 :(得分:0)

如果您使用的是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

答案 5 :(得分:0)

CT的CTE语法可能与Oracle不同(我在Teradata中运行),但我只使用CTE提供测试数据,即1 2 3和4.您可以使用临时表。实际的select语句是普通的SQL语言,它将存在于任何关系数据库中。

答案 6 :(得分:0)

正如其他人所建议的那样,UNION ALL可能是你在SQL中最好的选择。您可能还需要考虑在前端处理此问题,具体取决于您的具体要求。

答案 7 :(得分:-1)

对于Sql Server,请考虑将UNPIVOT替换为UNION:

SELECT id, value, colname
FROM #temp t
UNPIVOT (Value FOR ColName IN (value1,value2,value3)) as X

这也会返回列名。我不确定X用于什么,但你不能把它留下来。

答案 8 :(得分:-1)

试试这个:

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语句是普通的vanilla SQL,可以在任何数据库上运行。

^^^另外需要注意的事情。如果ID字段是数字,您可能需要将其转换为CHAR,以便将其与“值”连接。