【问题标题】:Grouping like records像记录一样分组
【发布时间】:2021-12-13 04:17:54
【问题描述】:

我们有一组数据,其中每个 CODE 有 2 条记录。数据示例如下:

TICKER    CODE    SCORE    PRICE    PCF
---------------------------------------
ABC        23       A       100      20
DEF        23       B       200      30
XXX        52       C       300      40
YYY        52       D       400      50
GHI        86       E       500      60
JKL        86       F       600      70
MNO        27       G       700      80
PQR        27       H       800      90

所以,我们需要做的是创建一个查询,它将通过 CODE 将类似记录的列返回到 1 条记录中,如下所示:

CODE,TICKER_1,SCORE_1,PRICE_1,PCF_1,TICKER_2,SCORE_2,PRICE_2,PCF_2
23,ABC,A,100,20,DEF,B,200,30
52,XXX,C,300,40,YYY,D,400,40
86,GHI,E,500,60,JKL,F,600,70
27,MNO,G,700,80,PQR,H,800,90

因此,它们通过 CODE 值组合在一起。

【问题讨论】:

    标签: sql oracle merge


    【解决方案1】:

    您可以尝试以下分配使用ROW_NUMBER 为每个代码条目分配一个行号,然后使用MAX 和一个case 表达式来过滤每个条目。

    例如。

    SELECT
        CODE,
        MAX(CASE WHEN rn=1 THEN TICKER END) AS TICKER_1,
        MAX(CASE WHEN rn=1 THEN SCORE END) AS SCORE_1,
        MAX(CASE WHEN rn=1 THEN PRICE END) AS PRICE_1,
        MAX(CASE WHEN rn=1 THEN PCF END) AS PCF_1,
        MAX(CASE WHEN rn=2 THEN TICKER END) AS TICKER_2,
        MAX(CASE WHEN rn=2 THEN SCORE END) AS SCORE_2,
        MAX(CASE WHEN rn=2 THEN PRICE END) AS PRICE_2,
        MAX(CASE WHEN rn=2 THEN PCF END) AS PCF_2
    FROM (
        SELECT 
            m.*, 
            ROW_NUMBER() OVER (PARTITION BY CODE ORDER BY TICKER) as rn 
        FROM mytable m
    ) m1
    GROUP BY
        CODE
    

    输出:

    CODE TICKER_1 SCORE_1 PRICE_1 PCF_1 TICKER_2 SCORE_2 PRICE_2 PCF_2
    23 ABC A 100 20 DEF B 200 30
    27 MNO G 700 80 PQR H 800 90
    52 XXX C 300 40 YYY D 400 50
    86 GHI E 500 60 JKL F 600 70

    出于调试目的,子查询的输出

        SELECT 
            m.*, 
            ROW_NUMBER() OVER (PARTITION BY CODE ORDER BY TICKER) as rn 
        FROM mytable m
    

    看起来像这样:

    TICKER CODE SCORE PRICE PCF RN
    ABC 23 A 100 20 1
    DEF 23 B 200 30 2
    MNO 27 G 700 80 1
    PQR 27 H 800 90 2
    XXX 52 C 300 40 1
    YYY 52 D 400 50 2
    GHI 86 E 500 60 1
    JKL 86 F 600 70 2

    View working demo on db fiddle

    值得注意的替代品

    • 除了CASE WHEN rn=1 THEN TICKER END,您还可以使用oracle 中的DECODE 函数DECODE(rn,1,TICKER)
    • 您也可以使用如下所示的数据透视表(注意。列名与预期结果不同
    WITH cte as (
        SELECT 
            m.*, 
            ROW_NUMBER() OVER (PARTITION BY CODE ORDER BY TICKER) as rn 
        FROM mytable m
    )
    SELECT * FROM cte 
    PIVOT (
        MAX(TICKER) as "TICKER",
        MAX(SCORE) as "SCORE",
        MAX(PRICE) as "PRICE",
        MAX(PCF) as "PCF"
        FOR rn IN (1,2)
    )
    

    输出:

    CODE 1_TICKER 1_SCORE 1_PRICE 1_PCF 2_TICKER 2_SCORE 2_PRICE 2_PCF
    23 ABC A 100 20 DEF B 200 30
    27 MNO G 700 80 PQR H 800 90
    52 XXX C 300 40 YYY D 400 50
    86 GHI E 500 60 JKL F 600 70

    View working demo on db fiddle here

    【讨论】:

    • 我认为这会奏效。查询有点大,但到目前为止我已经测试过,它似乎提供了正确的数据。非常感谢!
    • 我确实喜欢较小的查询,但是有什么方法可以让 1_ 或 2_ 到达另一边? _1 / _2 ?
    • @LandonStatis 从SELECT * 更改为使用带有别名的命名列。 SELECT "1_TICKER" as ticker1,
    • @LandonStatis MT0 是对的。请参阅db fiddle 中的示例,或者您可以尝试在您的 sql 客户端/应用程序中重命名它。
    • 只想对大家说声谢谢。这帮了大忙!
    猜你喜欢
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 2016-01-14
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多