And*_*Ray 38 postgresql left-join database-normalization
我正在Postgres中选择一些对象及其标签.架构非常简单,有三个表:
对象 id
引用的Tagging id | object_id | tag_id
标签 id | tag
我正在加入这样的表,array_agg用于将标签聚合到一个字段中:
SELECT objects.*,
array_agg(tags.tag) AS tags,
FROM objects
LEFT JOIN taggings ON objects.id = taggings.object_id
LEFT JOIN tags ON tags.id = taggings.tag_id
Run Code Online (Sandbox Code Playgroud)
但是,如果对象没有标签,Postgres会返回:
[ null ]
Run Code Online (Sandbox Code Playgroud)
而不是一个空数组.如果没有标签,如何返回空数组?我已经仔细检查过我没有返回null标签.
所述骨料文档说"聚结功能可用于在必要时代替零或空数组空".我试过COALESCE(ARRAY_AGG(tags.tag)) as tags但它仍然返回一个null数组.我试过让第二个参数很多东西(例如COALESCE(ARRAY_AGG(tags.tag), ARRAY()),但它们都会导致语法错误.
Tho*_*erl 31
另一种选择可能array_remove(..., NULL)(在9.3推出 IF)tags.tag是NOT NULL(否则你可能想保留NULL值的数组中,但在这种情况下,你不能在一个现有的区分NULL标记和NULL由于标签LEFT JOIN):
SELECT objects.*,
array_remove(array_agg(tags.tag), NULL) AS tags,
FROM objects
LEFT JOIN taggings ON objects.id = taggings.object_id
LEFT JOIN tags ON tags.id = taggings.tag_id
Run Code Online (Sandbox Code Playgroud)
如果未找到任何标记,则返回空数组.
Ale*_*nov 15
从9.4开始,可以限制聚合函数调用仅继续匹配特定条件的行: array_agg(tags.tag) filter (where tags.tag is not null)
Nic*_*nes 13
文档说当你聚合零行时,你得到一个空值,关于使用的注释COALESCE正在解决这个特定的情况.
这并不适用于您的查询,因为的方式LEFT JOIN表现-当它发现零点匹配的行,它返回一个排,用空值填充(和一个空行的聚集物是与一个空元素的数组).
你也许会盲目地更换[NULL]与[]输出,但你失去之间distiguish的能力,没有标签的物体和标签的对象,其中tags.tag为空.您的应用程序逻辑和/或完整性约束可能不允许第二种情况,但如果它确实设法潜入,则更有理由不抑制空标记.
您可以LEFT JOIN通过检查连接条件另一侧的字段是否为空来标识没有标记的对象(或者通常,告知何时找不到匹配项).所以在你的情况下,只需更换
array_agg(tags.tag)
Run Code Online (Sandbox Code Playgroud)
同
CASE
WHEN taggings.object_id IS NULL
THEN ARRAY[]::text[]
ELSE array_agg(tags.tag)
END
Run Code Online (Sandbox Code Playgroud)