Один SQL SELECT возврат нескольких строк из одной строки таблицы

у нас есть таблица, которая имеет вид:

ID,Value1,Value2,Value3
1,2,3,4

нам нужно преобразовать это в.

ID,Name,Value
1,'Value1',2
1,'Value2',3
1,'Value3',4

есть ли умный способ сделать это в одном операторе SELECT (i.e без союзов)? Имена столбцов Value1, Value2 и Value3 являются фиксированными и постоянными.

база данных oracle 9i.

9 ответов


это работает на 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 из dual union all select 2 из dual union all select 3 из dual) ofs" вместо этого. Злоупотребление рекурсивными запросами немного более общее - для Oracle. (Использование союзов для создания строк переносимо на другие DBs, хотя)


дать 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 означает, что сервер не будет выполнять distinct (что подразумевается в union операции). Это не должно иметь никакого значения с данными (так как ваши идентификаторы должны, надеюсь, отличаться), но это может немного ускорить его.


вы можете сделать это так, но это не красиво:

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

объединение всех, как предлагали другие, вероятно, ваш лучший выбор в SQL. Вы также можете рассмотреть возможность обработки этого в интерфейсе в зависимости от ваших конкретных требований.


синтаксис CTE может отличаться для Oracle (я запустил его в 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, чтобы объединить его с "Value".