如何转置具有可变但有限数量的匹配条目的表

时间:2016-02-09 09:32:07

标签: sql db2

我正在使用下表DDL:

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

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

我想创建一个查询,它为我提供了至少有一个类型为“t1”的记录的所有globalkeys,并将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

我在http://sqlfiddle.com/#!9/04855

下创建了一个SQLFiddle

我非常感谢任何有关如何完成此任务的指针!

再见,

马库斯

UPDATE#1:我在初始版本中没有说清楚BAR列中是否包含任意值,因此我不能使用@Mita语句的确切版本,因为这假设case语句中的值是固定的('hit1','hit2',...)。然而,与此同时,我发现使用row_number()窗口函数可以克服这个问题。看看我对@ Mita的答案的编辑。适当地更新了SQLFiddle ......

2 个答案:

答案 0 :(得分:1)

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 :(得分:0)

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

使用这个中间结果集,然后可以将表格转换为@ MITA的答案。

所以在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