如何在数组上进行左外部联接?

时间:2020-02-10 01:05:15

标签: sql postgresql jsonb

我在进行涉及jsonb数组的左外部联接时遇到麻烦。

我的模式:

CREATE TABLE IF NOT EXISTS cusips (
  name TEXT,
  cusip TEXT,
  ticker TEXT
);

CREATE TABLE IF NOT EXISTS companies (
  name TEXT,
  data JSONB
);

我的查询:

INSERT INTO cusips (name, cusip, ticker) VALUES
  ('Berkshire Official', '90210', 'BRKA'),
  ('Apple Corp', '90211', 'AAPL'),
  ('Microsoft Company', '90212', 'MSFT');

INSERT INTO companies (name, data) VALUES
  ('Berkshire', '{"tickers": ["BRKA", "BRKB"]}'),
  ('Apple', '{"tickers": ["AAPL"]}'),
  ('Microsoft', '{"tickers": ["MSFT"]}');

SELECT * FROM (SELECT name, cusip, ticker FROM cusips) c,
  LATERAL (
   SELECT jsonb_array_elements(data->'tickers') AS ticker
   FROM companies
   WHERE ticker::TEXT = 'BRKA'
  ) cc
WHERE c.cusip = '90210'

此查询返回:

name        cusip   ticker  ticker
Berkshire   90210   BRKA    "BRKA"
Berkshire   90210   BRKA    "BRKB"
Berkshire   90210   BRKA    "AAPL"
Berkshire   90210   BRKA    "MSFT"

我想要一行,其中包含名称,cusip和公司的所有数据(在这种情况下,这只是行情自动收录器)...例如:

name        cusip   data
Berkshire   90210   {"tickers": ["BRKA", "BRKB"]}

编辑:虽然我可以加入公司名称,但表之间的名称经常不同,所以我必须加入股票行情。

http://sqlfiddle.com/#!17/fa376/2

2 个答案:

答案 0 :(得分:2)

似乎您只想在表之间使用简单的JOIN

SELECT c.name, c.cusip, cc.data
FROM cusips c
JOIN companies cc ON cc.name= c.name
WHERE c.cusip = '90210'

输出:

name        cusip   data
Berkshire   90210   {"tickers": ["BRKA", "BRKB"]}

Demo on SQLFiddle

如果由于name列由于某些原因可能不匹配而必须在代码上进行匹配,则可以使用@>运算符检查tickers数组中是否存在代码:

SELECT c.name, c.cusip, cc.data
FROM cusips c
JOIN companies cc ON cc.data->'tickers' @> to_jsonb(c.ticker)
WHERE c.cusip = '90210'

输出:

name        cusip   data
Berkshire   90210   {"tickers": ["BRKA", "BRKB"]}

Demo on SQLFiddle

答案 1 :(得分:2)

尼克的答案似乎是最明智的答案。如果出于某种原因想要解构JSON并对其进行重构,则可以使用:

SELECT c.name, c.cusip, c.ticker, 
       jsonb_build_object('tickers', jsonb_agg(cc.ticker))
FROM cusips c CROSS JOIN LATERAL
     (SELECT jsonb_array_elements(co.data->'tickers') AS ticker
      FROM companies co
      WHERE co.name = c.name
     ) cc
WHERE c.cusip = '90210'
GROUP BY c.name, c.cusip, c.ticker;

Here是相应的db <>小提琴。