使用 Oracle SQL 在多个列上旋转多个组的最有效方法?

Posted

技术标签:

【中文标题】使用 Oracle SQL 在多个列上旋转多个组的最有效方法?【英文标题】:Most efficient way to pivot multiple groups over multiple columns using Oracle SQL? 【发布时间】:2020-08-28 21:11:20 【问题描述】:

任何人都可以帮助确定使用 Oracle SQL 在多个组中、跨多个列中透视数据的最有效方法吗?

我有一张如下表:

NAME    MEAL    FOOD    DRINK
Dan     Lunch   Taco    Coke
Dan     Dinner  Steak   Water
Becky   Lunch   Pizza   Coke
Becky   Dinner  Pizza   Milk

而我想要的输出如下表:

NAME    LUNCH_FOOD    LUNCH_DRINK    DINNER_FOOD    DINNER_DRINK
Dan     Taco          Coke           Steak          Water
Becky   Pizza         Coke           Pizza          Milk

执行此操作的最佳方法是什么?我下面的解决方案完成了任务,但我觉得有一种更有效的方法:

数据:

CREATE TABLE EXAMPLE (PERSON VARCHAR(10), MEAL VARCHAR(10), FOOD VARCHAR(10), DRINK VARCHAR(10));

INSERT INTO EXAMPLE (PERSON, MEAL, FOOD, DRINK) VALUES ('Dan', 'Lunch', 'Taco', 'Coke');
INSERT INTO EXAMPLE (PERSON, MEAL, FOOD, DRINK) VALUES ('Dan', 'Dinner', 'Steak', 'Water');
INSERT INTO EXAMPLE (PERSON, MEAL, FOOD, DRINK) VALUES ('Becky', 'Lunch', 'Pizza', 'Coke');
INSERT INTO EXAMPLE (PERSON, MEAL, FOOD, DRINK) VALUES ('Becky', 'Dinner', 'Pizza', 'Milk');

当前解决方案:

SELECT t1."PERSON",
       t1."FOOD" AS "LUNCH_FOOD",
       t1."DRINK" AS "LUNCH_DRINK",
       t2."FOOD" AS "DINNER_FOOD",
       t2."DRINK" AS "DINNER_DRINK"
  FROM (SELECT *
          FROM EXAMPLE
         WHERE "MEAL" = 'Lunch') t1
       FULL JOIN (SELECT *
                    FROM EXAMPLE
                   WHERE "MEAL" = 'Dinner') t2
          ON t1."PERSON" = t2."PERSON";

编辑:应该注意我在这里使用的是完全加入,因为在实际用例中存在一个人可能在一个组中但不是另一个人的实例(即,某人可能有午餐条目但没有相应的晚餐入口)。此外,可以假设每个人只有 1 顿午餐和 1 顿晚餐,永远不会更多。

【问题讨论】:

【参考方案1】:

我建议聚合:

select name,
       max(case when meal = 'Lunch' then food end) as lunch_food,
       max(case when meal = 'Lunch' then drink end) as lunch_drink,
       max(case when meal = 'Dinner' then food end) as dinner_food,
       max(case when meal = 'Dinner' then drink end) as dinner_drink
from example
group by name;

但是,如果您有一张大桌子,您可以将其与:

select name, l.food, l.drink, d.food, d.drink
from (select e.*
      from example e 
      where meal = 'Lunch'
     ) l full join
     (select e.*
      from dinner e 
      where meal = 'Dinner'
     ) d
     using (name);

Oracle 具有高效的聚合机制。很难说哪个会更快,所以你应该试试你的数据。

【讨论】:

【参考方案2】:
select *
from example
pivot (
max(FOOD) as FOOD,max(DRINK) as DRINK
for MEAL in ('Lunch' as Lunch,'Dinner' as Dinner)
);

结果:

PERSON     LUNCH_FOOD LUNCH_DRINK  DINNER_FOOD  DINNER_DRINK
---------- ---------- ------------ ------------ ------------
Becky      Pizza      Coke         Pizza        Milk
Dan        Taco       Coke         Steak        Water

【讨论】:

以上是关于使用 Oracle SQL 在多个列上旋转多个组的最有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 Oracle DBMS 中的多个列上使用过滤条件连接表

sql join 与列上的多个条件

SQL 内连接到同一个表,在多个列上,多次

SQL Server - 同一列上的多个 PIVOT

是否可以使用 SQL Server 使用相同的数据透视列进行多个数据透视

LINQ to SQL:多个列上的多个连接。这可能吗?