PostgreSQL 9.6。
create table jon.vins (vin citext primary key);
insert into jon.vins values
('3GNAXUEV1KL221776'),
('3GNAXHEV2KS548975');
CREATE TABLE jon.describe_vehicle (
vin citext primary key,
response jsonb);
jon.describe_vehicle
仅包含 1 vin、3GNAXHEV2KS548975 的数据;
这个查询:
select a.vin,
b.response->'attributes'->>'bestMakeName' as make
from jon.vins a
left join jon.describe_vehicle b on a.vin = b.vin;
返回我所期望的,每个 vin 在一行jon.vins
:
vin | make
-------------------+-----------
3GNAXUEV1KL221776 |
3GNAXHEV2KS548975 | Chevrolet
(2 rows)
但是这个查询:
select a.vin,
jsonb_array_elements(b.response->'style')->'attributes'->>'name' as style
from jon.vins a
left join jon.describe_vehicle b on a.vin = b.vin;
回报:
vin | style
-------------------+------------------
3GNAXHEV2KS548975 | FWD 4dr LS w/1LS
(1 row)
就好像jsonb_array_elements
在选择中将左连接变成了内连接。
我希望看到一行 vin 3GNAXUEV1KL221776 的样式为空值。
我究竟做错了什么?
集合返回函数应该放在 from 子句中。将它们放入 SELECT 子句是允许的,但会导致奇怪的结果(如您所见)。
干净的方法是:
在线示例:https ://rextester.com/RGY32895
它仍在执行左连接,只是有些行在冒泡到顶层之前被过滤掉了。这就是在查询的选择列表中设置返回函数的工作方式。如果你有一个包含文字 NULL 值的物理行,而不是由左连接生成的 NULL 值,它会做同样的事情。
解决此问题的一种方法是将 NULL 值替换为具有一个元素的合适的虚拟 JSON 数组:
如果您运行的是版本 10 或更高版本,另一种选择是使用始终返回一行的虚拟集合返回函数,并将其添加到您的选择列表中:
但这在 9.6 中不起作用。