当我在这里准备回答我们的一位同事时,我遇到了一个奇怪的情况,至少对我而言。最初的问题是:Pivot Table Omitting Rows that Have Null values
我已修改查询以使用max
代替group_concat
以显示"问题"在所有数据库中。
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
此查询的结果是:
ID FN LN JT
1 Sampo Kallinen Office Manager
2 Jakko Salovaara Vice President
3 (null) Foo No First Name
用户要求过滤标识为3
的行,因为字段value
为空。
当看起来很明显只需要做的就是在该查询上添加WHERE value IS NOT NULL
约束以实现用户期望的内容。它不会工作。
所以我开始在其他数据库上测试它以查看会发生什么(使用WHERE CLAUSE进行查询)
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE value is not null
GROUP BY id
令我惊讶的是,结果是一样的,没有效果。
然后我尝试了同一查询的不同版本:
SELECT * FROM (
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
) T
WHERE fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL
我能让它在所有数据库上运行的唯一方法就是使用此查询:
SELECT
id,
max(case when colID = 1 then value else '' end) AS fn,
max(case when colID = 2 then value else '' end) AS ln,
max(case when colID = 3 then value else '' end) AS jt
FROM tbl
WHERE NOT EXISTS (SELECT * FROM tbl b WHERE tbl.id=b.id AND value IS NULL)
GROUP BY id
所以我问:
这里发生了什么,除了Oracle的特定情况,所有其他数据库似乎都忽略了IS NOT NULL
过滤器?
答案 0 :(得分:4)
要忽略 结果 中的行(如果 源 行中的任何一行{{1 {}有} id
, Postgres 中的解决方案是在value IS NULL
中使用聚合函数every()
或(历史原因的同义词)bool_and()
}子句:
HAVING
您使用SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING every(value IS NOT NULL);
子句的尝试只会消除示例中WHERE
的一个源行(id = 3
的那一行),另外还有两个相同的colID = 1
。因此,在聚合后,我们仍会在结果中获得id
行。
但是由于我们没有id = 3
行,我们在colID = 1
的结果中为NULL
得到一个空字符串(注意:不是fn
值!)。
Postgres中更快的解决方案是使用id = 3
。详细说明:
虽然在SQL:2008标准中定义了crosstab()
,但许多RDBMS不支持它,可能是因为其中一些具有布尔类型的阴影实现。 (不要删除任何名称,如“MySQL”或“Oracle”......)。你可以在任何地方(包括Postgres)替换:
EVERY
因为SELECT id
, max(case when colID = 1 then value else '' end) AS fn
, max(case when colID = 2 then value else '' end) AS ln
, max(case when colID = 3 then value else '' end) AS jt
FROM tbl
GROUP BY id
HAVING count(*) = count(value);
不计算NULL值。在MySQL中还有bit_and()
。
更多相关问题:
答案 1 :(得分:2)
它在Oracle中有效,因为Oracle在NULL和''中错误地处理NULL。是相同的。其他数据库不这样做,因为它是错误的。 NULL是未知的,而不是''这只是一个空白的空字符串。
因此,如果你的where子句说WHERE (fn IS NOT NULL or fn <> '')
之类的东西你可能会更进一步。
答案 2 :(得分:0)
我认为这是一个HAVING子句可以满足你需要的情况。
SELECT id, max ... (same stuff as before)
FROM tbl
GROUP by id
HAVING fn IS NOT NULL
AND ln IS NOT NULL
AND jt IS NOT NULL