【问题标题】:Joining two joins in PostgreSQL在 PostgreSQL 中加入两个连接
【发布时间】:2021-07-26 06:34:01
【问题描述】:

背景

为了做一个关于汽车保险的数据分析项目,我需要从零开始快速学习一些 PostgreSQL。我有一个相当大的本地存储的 PostgreSQL 数据库(汽车和摩托车等车辆的保险索赔数据价值大约 8gb),我需要JOINUNION ALL 一些东西才能获得我的统计模型需要的表。

我需要做的第一部分是这件事,JOIN 在两个关于汽车索赔和摩托车索赔的表格之间的 UNION ALL

select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.service_date,
    h.principal_problem_cd,
    h.problem_code_vers_flag
from claims.auto_claims_line_items as l
JOIN claims.auto_claims_general h on l.claim_id = h.claim_id
UNION ALL
select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.entry_date as service_date,
    NULL as principal_problem_cd,
    NULL as problem_code_vers_flag
from claims.motorcycle_claims_line_items as l

这会产生一个看起来像这样的表格(列名缩写是为了美观):

cust_comb_id| claim_id | "Part_Cd" | svc_date | prin_prob_cd | prob_cd_vers_flg |
------------+----------+-----------+----------+--------------+------------------|
            |          |           |          |              |                  |

如您所见,汽车声明有一些列摩托车声明没有。这很好——我已经将它们填写为NULL,以便让UNION ALL 工作。现在,汽车索赔表很好地堆叠在摩托车索赔表的顶部。到目前为止,一切顺利。

到目前为止,我所做的第二部分是关于汽车和摩托车保险投保人(“客户”)的数据:

select m.customer_dob,
       m.customer_id,
       m.customer_gender_cd,
       m.customer_zip_cd,
       c.customer_combined_id
from customer."Customer" m
JOIN customer.customer_combined_crosswalk c on m.customer_id = c.customer_id 

结果如下:

dob | customer_id | gender_cd | zip_cd | cust_comb_id |
----+-------------+-----------+--------+--------------|
    |             |           |        |              |

问题

我已经弄清楚了我的数据操作的两半,但我不知道如何将这两半放在一起,可以这么说。我想(我想)在cust_comb_id 上加入这两件事,但我不知道该怎么写。当cust_comb_id 匹配时,我想保留第一部分中的所有内容(索赔数据)并从第二部分(投保人/客户)中引入数据,如果不匹配则给出空值。这是我正在寻找的视觉效果:

cust_comb_id| claim_id | "Part_Cd" | svc_date | prin_prob_cd | prob_cd_vers_flg |dob | cust_id | gender_cd | zip_cd |
------------+----------+-----------+----------+--------------+------------------|----+---------+-----------+--------+
            |          |           |          |              |                  |    |         |           |        |

我的尝试

我尝试使用子查询来加入这些连接,但我不断收到错误消息。 编辑

这是我尝试过的具体示例:

select * 
from
(select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.service_date,
    h.principal_problem_cd,
    h.problem_code_vers_flag
from claims.auto_claims_line_items as l
JOIN claims.auto_claims_general h on l.claim_id = h.claim_id
UNION ALL
select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.entry_date as service_date,
    NULL as principal_problem_cd,
    NULL as problem_code_vers_flag
from claims.motorcycle_claims_line_items as l) as cl
LEFT JOIN
select m.customer_dob,
       m.customer_id,
       m.customer_gender_cd,
       m.customer_zip_cd,
       c.customer_combined_id
from customer."Customer" m
JOIN customer.customer_combined_crosswalk c on m.customer_id = c.customer_id 

这会产生错误ERROR: syntax error at or near "select"

非常感谢任何帮助。

[注意:customer_combined_idcustomer_id 是两个不同的东西:combined id 是独一无二的,并且当客户从一个保险计划(他们有一个customer_id)切换到另一个保险计划时,他们得到了一个新的。]

【问题讨论】:

  • “我尝试使用子查询来加入这些连接,但我不断收到错误消息。”显示您尝试过的内容以及遇到的错误类型。是 SQL 错误还是逻辑错误?
  • 谢谢,@Alex Yu。请参阅我对帖子末尾的编辑,其中包含我尝试过的代码及其引发的错误。
  • 啊!所以这是一个语法问题。看看db-fiddle.com/f/msAtD89dn4DndMtxukkgkP/2。这看起来像是您想要实现的目标吗?
  • 啊,是的!我一直在思考如何写第二部分。顺便说一句,在我编辑了原始帖子之后,我开始摆弄视图:我基本上让第一部分和第二部分各有自己的视图,然后写了一个看起来更n00b的连接来把它们放在一起——它奏效了!我正在考虑发布它来回答我自己的问题,但我更愿意为你的回答感谢你。绝对将其发布为答案!
  • “我基本上让第一部分和第二部分各有自己的观点”——当 CTE 出现在 DB2 (IIRC) 中时,它们被称为“临时视图”——所以你非常接近 CTE 的解决方案

标签: sql postgresql join


【解决方案1】:

所以这是一个语法问题。

OP 已经拥有所有需要的部分:

  • 第一部分和第二部分子查询已经实现
  • 已定义如何加入他们

唯一的问题是语法问题。

我想这个表格是最易读的:

WITH PartI AS(
 select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.service_date,
    h.principal_problem_cd,
    h.problem_code_vers_flag
from claims.auto_claims_line_items as l
JOIN claims.auto_claims_general h on l.claim_id = h.claim_id
UNION ALL
select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.entry_date as service_date,
    NULL as principal_problem_cd,
    NULL as problem_code_vers_flag
from claims.motorcycle_claims_line_items as l 
), 
PartII AS (
  select customer_dob,
       customer_id,
       customer_gender_cd,
       customer_zip_cd,
       customer_combined_id
from customer."Customer"  m
JOIN customer.customer_combined_crosswalk c on m.customer_id = c.customer_id 
) 
SELECT 
        * 
    FROM
        PartI P1
        LEFT JOIN PartII P2 
          ON P1.customer_combined_id = P2.customer_combined_id;

https://www.db-fiddle.com/f/msAtD89dn4DndMtxukkgkP/2

【讨论】:

  • 在运行代码后我现在注意到一些事情:生成的数据集包含的行数大约是我预期的 3 倍——大约 300,000。单独运行的“Part I”会生成一个包含 100k 行的表,而单独运行“Part II”会生成一个包含 3k 行的表。我只打算获得与第一部分相同的 100k 的结果。有什么见解吗?如果没有,请不要担心,我很乐意提出自己的问题。谢谢亚历克斯。
  • 首先显而易见的是查看JOIN customer.customer_combined_crosswalk 每个customer_id 是否包含超过1 行。看看SELECT customer_id, COUNT(*) FROM customer_combined_crosswalk GROUP BY customer_id HAVING COUNT(*) >1
  • 另一部分:看PartI是否有重复:SELECT customer_combined_id, COUNT(*) from PartI GROUP BY customer_combined_id HAVING COUNT(*) > 1
  • 谢谢,这揭示了问题:“第二部分”中应该只有 ~1k 行,而有 ~3k!这意味着每个 customer_combined_id 在右侧 (RHS) 表中出现近 3 次。这意味着对于第一部分中的每个 customer_combined_idLEFT JOIN 找到了 3 个左右的匹配项,最终行数增加了三倍。我将删除重复的 customer_combined_id's 并使用新的“第二部分”重新运行解决方案。再次感谢先生。
【解决方案2】:

Alex Yu 的回答更好,但我想发布这个是因为 a) 它也有效,b) 显示了 SQL 中视图的巧妙用途。

获取第一部分,并通过在第一个 select 之前添加一行 CREATE OR REPLACE VIEW 来查看它:

CREATE OR REPLACE VIEW clms AS
select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.service_date,
    h.principal_problem_cd,
    h.problem_code_vers_flag
from claims.auto_claims_line_items as l
JOIN claims.auto_claims_general h on l.claim_id = h.claim_id
UNION ALL
select
    l.customer_combined_id,
    l.claim_id,
    l."Part_Cd",
    l.entry_date as service_date,
    NULL as principal_problem_cd,
    NULL as problem_code_vers_flag
from claims.motorcycle_claims_line_items as l

接下来,对第二部分做同样的事情:

CREATE OR REPLACE VIEW cstmr AS
select m.customer_dob,
       m.customer_id,
       m.customer_gender_cd,
       m.customer_zip_cd,
       c.customer_combined_id
from customer."Customer" m
JOIN customer.customer_combined_crosswalk c on m.customer_id = c.customer_id 

最后,对两个视图进行 SQL 101 级别的简单连接:

select *
from clms
join cstmr m on clms.customer_combined_id = customer_combined_id

我在发布问题后遇到了这个答案,很高兴自己找到了一个(有点)优雅的解决方案。

【讨论】:

  • 对于不支持 CTE 的古代引擎来说,这是绝对有效的解决方案。例如。 MSSQL 2000 或古代神谕。但是您可以像使用视图一样使用子查询。
猜你喜欢
  • 2015-09-10
  • 1970-01-01
  • 1970-01-01
  • 2018-02-28
  • 2020-09-13
  • 2011-08-07
  • 2020-05-02
  • 2014-05-31
  • 1970-01-01
相关资源
最近更新 更多