2017-01-25 2 views
2

То, что я в настоящее время имеют:Oracle SQL столбцы в строки без UNPIVOT

Team User Apples Oranges Pears 
Red  Adam 4   5   6 
Red  Avril 11  12   13 
Blue David 21  22   23 

Что необходимо:

Team User Product Count 
Red  Adam Apples  4 
Red  Adam Oranges 5 
Red  Adam Pears  6 
Red  Avril Apples  11 
Red  Avril Oranges 12 
Red  Avril Pears  13 
Blue David Apples  21 
.... 

Это должно быть реализовано с использованием Oracle SQL. Я понимаю, что это можно сделать с помощью UNPIVOT, но моя версия Oracle SQL слишком старая, чтобы поддерживать этот метод. Может ли кто-нибудь привести пример того, как достичь этого, используя CROSS APPLY или эквивалентные методы? Подсчет изменений в зависимости от комбинации командных пользователей и количества видов продукции может немного измениться в будущем, поэтому может потребоваться масштабируемое решение.

Это чувствительный ко времени, поэтому я ценю помощь.

+2

Вы можете сделать это, используя серию союзов, но это было бы довольно уродливо. Вы еще что-то пробовали? –

+1

'select team,« USER », яблоки в качестве продукта из the_table union все выбирают команду« USER », апельсины из таблицы_таблицы ...' –

ответ

2

Вы можете сделать это с помощью кросс-соединения и некоторых операторов case с помощью фиктивного подзапроса, который содержит столько же строк, сколько у вас есть столбцы, которые вы хотите отключить (так как вы хотите, чтобы каждый столбец переходил в свою собственную строку) как так:

WITH your_table AS (SELECT 'Red' Team, 'Adam' usr, 4 Apples, 5 Oranges, 6 Pears FROM dual UNION ALL 
        SELECT 'Red' Team, 'Avril' usr, 11 Apples, 12 Oranges, 13 Pears FROM dual UNION ALL 
        SELECT 'Blue' Team, 'David' usr, 21 Apples, 22 Oranges, 23 Pears FROM dual) 
-- end of mimicking your table. See SQL below: 
SELECT yt.team, 
     yt.usr, 
     CASE WHEN d.id = 1 THEN 'Apples' 
      WHEN d.id = 2 THEN 'Oranges' 
      WHEN d.id = 3 THEN 'Pears' 
     END product, 
     CASE WHEN d.id = 1 THEN yt.apples 
      WHEN d.id = 2 THEN yt.oranges 
      WHEN d.id = 3 THEN yt.pears 
     END count_of_product 
FROM your_table yt 
     CROSS JOIN (SELECT LEVEL ID 
        FROM dual 
        CONNECT BY LEVEL <= 3) d -- number of columns to unpivot 
ORDER BY team, usr, product; 

TEAM USR PRODUCT COUNT_OF_PRODUCT 
---- ----- ------- ---------------- 
Blue David Apples    21 
Blue David Oranges    22 
Blue David Pears     23 
Red Adam Apples     4 
Red Adam Oranges    5 
Red Adam Pears     6 
Red Avril Apples    11 
Red Avril Oranges    12 
Red Avril Pears     13 

Действовать таким образом означает, что у вас есть только пройти через таблицу один раз, а не несколько раз, если вы делаете профсоюз весь метод.


ETA: Вот метод, который Алексей имел в виду - я хотел бы предложить тестирование обоих методов против вашего набора данных (который, мы надеемся, достаточно большой, чтобы быть репрезентативной), чтобы увидеть, какая из них более производительным:

WITH your_table AS (SELECT 'Red' Team, 'Adam' usr, 4 Apples, 5 Oranges, 6 Pears FROM dual UNION ALL 
        SELECT 'Red' Team, 'Avril' usr, 11 Apples, 12 Oranges, 13 Pears FROM dual UNION ALL 
        SELECT 'Blue' Team, 'David' usr, 21 Apples, 22 Oranges, 23 Pears FROM dual) 
-- end of mimicking your table. See SQL below: 
SELECT yt.team, 
     yt.usr, 
     CASE WHEN LEVEL = 1 THEN 'Apples' 
      WHEN LEVEL = 2 THEN 'Oranges' 
      WHEN LEVEL = 3 THEN 'Pears' 
     END product, 
     CASE WHEN LEVEL = 1 THEN yt.apples 
      WHEN LEVEL = 2 THEN yt.oranges 
      WHEN LEVEL = 3 THEN yt.pears 
     END count_of_product 
FROM your_table yt 
CONNECT BY PRIOR team = team 
      AND PRIOR usr = usr 
      AND PRIOR sys_guid() IS NOT NULL 
      AND LEVEL <= 3 
ORDER BY team, usr, product; 

TEAM USR PRODUCT COUNT_OF_PRODUCT 
---- ----- ------- ---------------- 
Blue David Apples    21 
Blue David Oranges    22 
Blue David Pears     23 
Red Adam Apples     4 
Red Adam Oranges    5 
Red Adam Pears     6 
Red Avril Apples    11 
Red Avril Oranges    12 
Red Avril Pears     13 
+0

Мне нравится этот подход; Я считаю, что вы могли бы даже упростить его, удалив 'JOIN' и применяя' CONNECT BY' непосредственно в исходной таблице, без необходимости 'DUAL' – Aleksej

+0

@Aleksej Я не считал это; это возможно, но я не знаю, будет ли это так же результативно. К сожалению, у меня нет времени, чтобы проверить это. – Boneist

+0

Этот подход решил мою проблему и сократил значительное количество человеко-часов. Однако я хотел бы узнать больше идеи Алексея, не могли бы вы предоставить более подробную информацию? – Toon

1

Вы можете использовать большой союз все так:

select 
    Team, 
    "User", 
    'Apples' Product, 
    Apples "Count" 
from your_table 
union all 
select 
    Team, 
    "User", 
    'Oranges' Product, 
    Oranges "Count" 
from your_table 
union all 
select 
    Team, 
    "User", 
    'Pears' Product, 
    Pears "Count" 
from your_table 
union all 
. . . 

Кроме того, старайтесь не использовать ключевые слова, такие, как пользователя или графа в качестве идентификаторов или еще, завернуть их в двойных кавычках, как я сделал ,

Смежные вопросы