从硬编码的列值列表中查找第一行(Pivot问题?)

时间:2009-12-04 11:05:52

标签: sql db2

我试图从满足某些条件的“第一”行中提取列值,其中“first”由列值的硬编码列表定义。不幸的是我是一个SQL业余爱好者。我正在使用DB2。

我这样做效率不高:

SELECT COALESCE(
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2" AND COL = 'A'), 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2" AND COL = 'B'), 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2" AND COL = 'C'), 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2" AND COL = 'D') 
)

这里的问题是SOMETABLE非常大。所以我想做一些像:

SELECT COALESCE(
  (SELECT COL FROM T WHERE COL = 'A'), 
  (SELECT COL FROM T WHERE COL = 'B'), 
  (SELECT COL FROM T WHERE COL = 'C'), 
  (SELECT COL FROM T WHERE COL = 'D') 
)
FROM 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2") AS T

这是无效的,因为我无法引用T表。

假设上面的T包含以下行:

'E'
'B'
'D'

然后我想选择'B',因为它是COALESCE语句中指定的第一个值。

我意识到通过做类似的事情,我可以更接近我想要的东西:

SELECT 
  (CASE COL WHEN 'A' THEN COL ELSE NULL END), 
  (CASE COL WHEN 'B' THEN COL ELSE NULL END), 
  (CASE COL WHEN 'C' THEN COL ELSE NULL END),
  (CASE COL WHEN 'D' THEN COL ELSE NULL END)
FROM 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2") AS T

这产生了结果:

-   -   -   -
-   -   -   D
-   B   -   -

现在我想把它聚合或“扁平”成一行,如下所示:

-   B   -   D

然后我会简单地在列上合并。

任何建议都将不胜感激!

4 个答案:

答案 0 :(得分:1)

根据您的问题提供您的硬编码值排序,然后:

SELECT COL   
FROM SOMETABLE   
WHERE X = "txt1"   
AND Y = "txt2"   
ORDER BY col   
fetch first 1 rows only

答案 1 :(得分:0)

我想我找到了解决方案。

SELECT COALESCE(
  MAX(CASE COL WHEN 'A' THEN COL ELSE NULL END), 
  MAX(CASE COL WHEN 'B' THEN COL ELSE NULL END), 
  MAX(CASE COL WHEN 'C' THEN COL ELSE NULL END),
  MAX(CASE COL WHEN 'D' THEN COL ELSE NULL END))
FROM 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2") AS T

请告诉我这是愚蠢还是错误。

答案 2 :(得分:0)

如果我理解你的问题,你可以转换

SELECT COALESCE(  
    (SELECT COL FROM T WHERE COL = 'A'),   
    (SELECT COL FROM T WHERE COL = 'B'),   
    (SELECT COL FROM T WHERE COL = 'C'),   
    (SELECT COL FROM T WHERE COL = 'D') )
FROM   (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2") AS T

到CTE,如下:

WITH T AS (
    SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2"
)
SELECT COALESCE(  
    (SELECT COL FROM T WHERE COL = 'A'),   
    (SELECT COL FROM T WHERE COL = 'B'),   
    (SELECT COL FROM T WHERE COL = 'C'),   
    (SELECT COL FROM T WHERE COL = 'D') )
FROM T;

或类似的东西。我无法测试它,因为我没有DB2数据库。

答案 3 :(得分:0)

你非常接近这个......

SELECT COALESCE(
  MAX(CASE COL WHEN 'A' THEN COL ELSE NULL END), 
  MAX(CASE COL WHEN 'B' THEN COL ELSE NULL END), 
  MAX(CASE COL WHEN 'C' THEN COL ELSE NULL END),
  MAX(CASE COL WHEN 'D' THEN COL ELSE NULL END))
FROM 
  (SELECT COL FROM SOMETABLE WHERE X = "txt1" AND Y = "txt2") AS T

您不需要coalesce(不能在多个列周围使用它)并且您不需要子查询(始终首先评估where子句)

SELECT MAX(CASE WHEN COL = 'A' THEN COL ELSE NULL END) AS A, 
       MAX(CASE WHEN COL = 'B' THEN COL ELSE NULL END) AS B, 
       MAX(CASE WHEN COL = 'C' THEN COL ELSE NULL END) AS C,
       MAX(CASE WHEN COL = 'D' THEN COL ELSE NULL END) AS D
  FROM SOMETABLE 
 WHERE X = "txt1" 
   AND Y = "txt2"

某些数据库支持ANSI SQL标准PIVOT函数,该函数执行类似(但不完全相同)的操作。听起来不像DB2 / 400有许多高级功能。