如何包含不符合条件的行?

How do I include rows that don't meet the criteria?

我知道我可能只是想错了。我有以下结构:

  CREATE TABLE mytable (
  id       serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data     jsonb
);

以及以下数据:

INSERT INTO mytable (employee, data)
VALUES
 ('Jim', '{"sales": [{"value": 10, "yr": "2010"}, {"value": 5, "yr": "2011"}, {"value": 40, "yr": "2012"}]}'),
 ('Rob', '{"sales": [{"value": 10, "yr": "2009"}, {"value": 5, "yr": "2010"}, {"value": 41, "yr": "2011"}]}')

我正在尝试 return 所有员工及其 2012 年的 "value" 销售额。如果 2012 年没有销售额,则 return "No Data"。我有:

SELECT id, employee, 
coalesce((SELECT s.value AS value FROM mytable, jsonb_to_recordset(mytable.data->'sales') AS s(yr text, value float)
WHERE s.yr='2012'), 0) AS b FROM mytable

我得到:

id |employee |b
53 |Jim      |40 
54 |Rob      |40

'Rob' 的值是错误的。应该是'No Data'。 (我使用 0 作为合并的第二个参数,因为出现错误 "invalid input syntax for type double precision: 'No Data'"

问题是您的 inner SELECT 实际上并没有过滤员工的 ID。因此,Jim 的 40 也被选为 Rob。

如果您插入另一个具有 2012 年值的员工,实际上更容易看到。
你会得到

ERROR:  21000: more than one row returned by a subquery used as an expression

因为 SELECT value FROM ... WHERE yr = '2012' 会 return 多个值,即您(基本上)会要求(假设第二个员工有 41 个销售额)

SELECT COALESCE((VALUES (40), (41)));

您可以使用 CTE(虽然可能不是最有效的方法):

WITH sales_2012 AS (
  SELECT id, s.value
  FROM mytable,
       jsonb_to_recordset(mytable.data->'sales') AS s(yr text, value float)
  WHERE s.yr='2012'
)
SELECT employee, COALESCE(value, 0)       
FROM mytable
LEFT OUTER JOIN sales_2012
ON mytable.id = sales_2012.id
;
┌──────────┬────────┐
│ employee │ value  │
├──────────┼────────┤
│ Jim      │     40 │
│ Rob      │      0 │
└──────────┴────────┘

关键元素是使用LEFT JOIN LATERAL而不是隐含的CROSS JOIN LATERAL作为缩写只有一个逗号被解释。

  • Call a set-returning function with an array argument multiple times

查询可以简单地是:

SELECT t.id, t.employee, s.*
FROM   mytable t
LEFT   JOIN LATERAL jsonb_to_recordset(t.data->'sales')
                 AS s(yr int, value int) ON s.yr = 2012;

我们可以立即方便地挑选 yr = 2012 的销售人员,而不会因结果而流失员工。

要用 'NO Data' 美化,value 列必须是匹配的字符串类型:

SELECT t.id, t.employee
     , COALESCE(s.yr, 2012) AS yr
     , COALESCE(s.value, 'No Data') AS value
FROM   mytable t
LEFT   JOIN LATERAL jsonb_to_recordset(t.data->'sales')
                 AS s(yr int, value text) ON s.yr = 2012;

基于这些缺失的(可能的)细节:

  • table 中每个员工恰好一行:empoyeeUNIQUE NOT NULL
  • 每个员工在 data 中可以有 0-n 年的销售额 - data 可以为 NULL。

  • yrvalue 存储有效整数。否则调整类型。

正确的table定义:

CREATE TABLE mytable (
  id       serial PRIMARY KEY
, employee text UNIQUE NOT NULL
, data     jsonb
);

什么是 LATERAL JOIN

根据评论中的要求,这些链接应该有所帮助,尤其是初学者的第一个链接: