2

I know I'm probably just thinking about this wrong. I have the following structure:

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

And the following data:

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"}]}')

I'm trying to return all the employees and the "value" of their sales in 2012. If there is no sales in 2012 then return "No Data". I have:

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

I get:

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

The value is wrong for 'Rob'. It should be 'No Data'. (I am using 0 as the 2nd parameter for coalesce as I get an error "invalid input syntax for type double precision: 'No Data'"

4

2 回答 2

0

关键元素是使用而LEFT JOIN LATERAL不是隐式CROSS JOIN LATERAL解释仅包含逗号的短记号。

查询可以简单地是:

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;

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

  • 表中每个员工正好有一行:empoyeeis UNIQUE NOT NULL.
  • 每个员工可以有 0-n 年的销售额data-data可以为 NULL。

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

正确的表定义:

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

什么是LATERAL JOIN

根据评论中的要求,这些链接应该会有所帮助,尤其是对于初学者来说:

于 2015-07-10T01:49:58.883 回答
0

问题是您的内部 SELECT实际上并没有过滤员工的身份。因此,吉姆的 40 岁也被罗伯选中。

实际上,如果您插入另一个值为 2012 年的员工,则实际上要容易得多。
您会得到

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

因为SELECT value FROM ... WHERE yr = '2012'会返回多个值,即您(基本上)会要求(假设第二名员工有 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 │
└──────────┴────────┘
于 2015-07-09T21:59:55.033 回答