如何使用可变但数量有限的匹配条目转置 table

How to transpose a table with a variable but limited number of matching entries

我正在使用以下 table DDL:

 CREATE TABLE foo (
   globalkey INTEGER NOT NULL,   
   subkey INTEGER NOT NULL,   
   type VARCHAR(3) NOT NULL,   
   bar VARCHAR(4) NOT NULL 
  );

table 包含不同类型的记录(例如 "t1"、"t2" 和 "t3")。 table 的主键是 (globalkey, subkey)。对于每个全局键,可以有 1-n 条记录,其中一些可能共享相同的类型。但是只有 0-3 条类型为 "t1".

的记录

我想创建一个查询,为我提供至少有一个类型为 "t1" 和 returns 的所有全局键,结果中的 3 个栏值作为 3 个不同的列。

所以对于给定的数据:

GLOBALKEY, SUBKEY, TYPE, BAR
1          1     t1     hit1
1          28    t1     hit1234
1          315   t2     miss
1          967   t1     hit4711
2          1     t5     miss
2          13    t5     miss
2          18    t1     hit9876
3          1     t2     miss

我想得到:

GLOBALKEY, BAR1,   BAR2,   BAR3
1,         "hit1", "hit1234", "hit4711"
3,         "hit9876",  NULL , NULL

我在下面创建了一个 SQLFiddle:http://sqlfiddle.com/#!9/04855

对于如何完成此操作的任何指示,我将不胜感激!

再见,

马库斯

更新 #1:在我的初始版本中,我没有足够清楚地说明 BAR 列包含任意值,因此我无法使用 @Mita 语句的确切版本,因为这假定了case 语句是固定的('hit1'、'hit2'、...)。但是与此同时,我发现了如何使用 row_number() window 函数来克服这个问题。查看我对@Mita 答案的编辑。相应地更新了 SQLFiddle...

JSFiddle 插入内容与您在示例中提供的数据不一致。正确的数据应该是:

INSERT INTO foo VALUES (1,1,'t1','hit1');
INSERT INTO foo VALUES (1,28,'t1','hit2');
INSERT INTO foo VALUES (1,315,'t2','miss');
INSERT INTO foo VALUES (1,967,'t1','hit3');
INSERT INTO foo VALUES (2,1,'t5','miss');
INSERT INTO foo VALUES (2,13,'t5','miss');
INSERT INTO foo VALUES (2,18,'t1','hit1');
INSERT INTO foo VALUES (3,1,'t2','miss');

查询(如果我没理解错的话)应该是:

SELECT
    globalkey,
    MAX(CASE WHEN bar = 'hit1' THEN 'hit1' ELSE NULL END) AS bar1,
    MAX(CASE WHEN bar = 'hit2' THEN 'hit2' ELSE NULL END) AS bar2,
    MAX(CASE WHEN bar = 'hit3' THEN 'hit3' ELSE NULL END) AS bar3
FROM
    foo
WHERE
    type = 't1'
GROUP BY
    globalkey

更新 #1:Mita 的查询假定 'hit1'、'hit2'、... 是固定值。在我的示例中,它们没有被枚举,但可以是任何文本。但是,通过使用 window 函数,您可以实现我想要的。首先 select 所有匹配行 (type='t1') 并在当前全局键中添加一个包含行号的新列。

使用这个中间结果集,然后可以转置类似于@MITA 答案的table。

所以在 DB2 中你可以这样做:

WITH tmp1 AS (SELECT globalkey, bar, row_number() OVER (partition by globalkey) AS rnr
WHERE  
    type='t1'
)

SELECT globalkey,
    MAX(CASE WHEN rnr = 1 THEN bar ELSE NULL END) AS bar1,
    MAX(CASE WHEN rnr = 2 THEN bar ELSE NULL END) AS bar2,
    MAX(CASE WHEN rnr = 3 THEN bar ELSE NULL END) AS bar3
FROM
    foo
WHERE
    type = 't1'
GROUP BY
    globalkey