SQL结合结果

时间:2016-04-27 22:34:26

标签: sql postgresql

以下查询返回客户,地址和计划之间1对多关系的值

SELECT customers.name, 
  addresses.address, 
  plans.state, 
  plans.created, 
  plans.updated
FROM addresses INNER JOIN plans ON addresses.id = plans.address_id
 INNER JOIN customers ON customers.id = addresses.customer_id

查询将以下面的格式返回数据:

    name    |   address     |   state   |   created     |   updated
-----------------------------------------------------------------------
Larry Smith |   123 St.     |   Active  |   04/20/2016  |   04/20/2016

Larry Smith |   123 St.     |   Inactive|   03/20/2016  |   04/20/2016

Larry Smith |   123 St.     |   Inactive|   02/20/2016  |   03/20/2016

Jane Doe    |   456 St.     |   Inactive|   03/20/2016  |   04/20/2016  

Jane Doe    |   456 St.     |   Inactive|   02/20/2016  |   03/20/2016  

我希望它显示每个客户只显示一次的数据。创建的字段是创建的第一个计划的日期,更新的字段是最后一个计划的更新,状态字段是最后一个计划的状态

这是一个例子:

    name    |   address     |   state   |   created     |   updated
-----------------------------------------------------------------------

Larry Smith |   123 St.     |   Active  |   02/20/2016  |   04/20/2016

Jane Doe    |   456 St.     |   Inactive|   02/20/2016  |   04/20/2016

我尝试在地址上使用Distinct或Group by,但由于计划具有不同的ID,因此每个客户仍会显示多个条目,并且它无法满足在单个记录中组合计划中的日期的要求

修改 澄清:我使用的是Postgresql

我根据Gordon和Firetonton提供的查询和postgresql上的一些文档尝试了这个查询

SELECT customers.id, customers.name, 
  addresses.address, 
  FIRST_VALUE(plans.state) OVER w,
  MIN(plans.created) as created_plan, 
  MAX(plans.updated) as cancelled_plan
FROM addresses
 INNER JOIN plans ON addresses.id = plans.address_id
 INNER JOIN customers ON customers.id = addresses.customer_id

WINDOW w as(
  PARTITION BY plans.state ORDER BY plans.updated DESC
)

GROUP BY customers.id, customers.name, addresses.address, "plans".state

我得到了Error : ERROR: syntax error at or near "GROUP"

提前致谢

2 个答案:

答案 0 :(得分:1)

你必须在GROUP BY的补充中使用聚合函数MIN,MAX和FIRST(... ORDER BY ...):

SELECT customers.name, 
  addresses.address, 
  -- With "first" custom aggregate
  -- FIRST(plans.state ORDER BY plans.updated DESC), -- or ...plans.created... if it's your reference
  -- Or with postgres array_agg, makes an array an take the first value
  (array_agg(plans.state ORDER BY plans.updated))[1] AS last_state,
  MIN(plans.created), 
  MAX(plans.updated)
FROM addresses
 INNER JOIN plans ON addresses.id = plans.address_id
 INNER JOIN customers ON customers.id = addresses.customer_id
GROUP BY customers.name, addresses.address

答案 1 :(得分:1)

您想为此使用聚合。我将建议条件聚合:

SELECT name, address, 
       max(case when seqnum = 1 then state end) as last_state,
       min(created) as created, max(updated) as updated
FROM (SELECT c.name, a.address, p.state, p.created, p.updated,
             ROW_NUMBER() OVER (PARTITION BY c.id ORDER BY p.updated DESC) as seqnum
      FROM addresses a INNER JOIN
           plans p
           ON a.id = p.address_id INNER JOIN
           customers c
           ON c.id = a.customer_id
     ) apc
GROUP BY name, address;