postgresql一对多作为json的结果,如何过滤?

问题描述 投票:0回答:2

我有一个简单的数据库结构,具有一对多的关系

CREATE TABLE customer (
  id                              SERIAL PRIMARY KEY,
  email                           TEXT,
  first_name                      TEXT,
  last_name                       TEXT
);

CREATE TABLE customer_address (
  id              SERIAL PRIMARY KEY,
  customer_id     INTEGER                NOT NULL,
  street_name     TEXT                   NOT NULL,
  street_number   TEXT                   NOT NULL,
  zip_code        TEXT                   NOT NULL,
  city            TEXT                   NOT NULL
);

对于我的应用程序,我想将每个客户的所有地址作为一行返回,我将所有地址封装在json数组中。这样做是这样的:

SELECT customer.*, 
       addresses 
FROM   customer 
       left join (SELECT 
Array_to_json(Array_agg( 
Json_build_object('id', address.id, 'street_name', address.street_name, 'street_number', address.street_number, 'zip_code', address.zip_code, 'city', address.city))) AS addresses,
address.customer_id 
AS customer_id 
 FROM   customer_address AS address 
 GROUP  BY address.customer_id) addresses 
       ON addresses.customer_id = customer.id 
join customer_address 
  ON customer_address.customer_id = customer.id 

这样可以正常工作,并为每个结果提供一个结果集,其中包含一个名为addresses的元素,其中包含所有客户地址的JSON数组。

现在我想选择所有客户(包括他们所有的地址),其street_name就像某个搜索词。我无法让它发挥作用。当一个地址的街道名称包含某个值(与ILIKE匹配)时,如何选择包括所有内联地址的完整记录?

我尝试添加:WHERE customer_address.street_name LIKE 'Ro',虽然这有效,但如果我用完全不同的东西替换这个where语句,例如WHERE customer.id > 0,我在结果集中得到双打

这是一个sql小提琴玩:

http://sqlfiddle.com/#!17/0e818/4

sql postgresql
2个回答
2
投票

此连接条件看起来错误:

JOIN customer_address ON customer_address.id = customer.id

不应该

JOIN customer_address ON customer_address.customer_id = customer.id

这是小提琴:http://sqlfiddle.com/#!17/2fff0/6

在对原始答案进行讨论之后,这是解决问题的最终解决方案:

http://sqlfiddle.com/#!17/2fff0/25


1
投票

这是否涵盖了您的预期结果?

SELECT customer.*,addresses
FROM customer 
LEFT JOIN  (SELECT array_to_json(array_agg(json_build_object('id',address.id,'street_name',address.street_name,'street_number',address.street_number,'zip_code',address.zip_code,'city',address.city))) AS addresses,address.customer_id AS customer_id 
            FROM customer_address AS address 
            GROUP BY address.customer_id) addresses 
ON addresses.customer_id = customer.id    
JOIN customer_address ON customer_address.id = customer.id
WHERE customer_address.street_name LIKE 'Ro%'
id | email         | first_name | last_name | addresses                                                                                                                                                                                       
-: | :------------ | :--------- | :-------- | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 1 | [email protected] | John       | Doe       | [{"id" : 1, "street_name" : "Route", "street_number" : "222", "zip_code" : "9000", "city" : "NY"},{"id" : 2, "street_name" : "Ro", "street_number" : "444", "zip_code" : "9000", "city" : "LA"}]

dbfiddle here

© www.soinside.com 2019 - 2024. All rights reserved.