如何避免使用完全外部联接时产生歧义?

时间:2018-11-28 13:12:31

标签: sql postgresql join

我有三个表需要联接。

如果我在下面的查询中使用“ P_SERIAL_ID”,“ CONTACT_NOTE”等多个列,则可能会模棱两可。

“ P_SERIAL_ID”和“ CONTACT_NOTE”是属于“ B_COLLECTION”,“ COLLECTION_CONSENT_RC”和“ B_TRACE”,“ P_TC_RC”的列。 “ B_TRACE”。“ P_TC_DATA”没有这两列。

如何解决此问题?

SELECT "P_SERIAL_ID","CONTACT_NOTE" 
FROM (
  SELECT * 
  FROM "B_TRACE"."P_TC_DATA" AS DAT
    FULL OUTER JOIN "B_COLLECTION"."COLLECTION_CONSENT_RC" AS SUBID ON DAT."P_SERIAL_ID" = SUBID."SUBJECT_ID"
    FULL OUTER JOIN "B_TRACE"."P_TC_RC" AS TR ON TR."P_SERIAL_ID" = DAT."P_SERIAL_ID"
  WHERE DAT."STATE_ID" IN ('7','8','9')
) AS SHIT0 
WHERE "SUBJECT_CITIZEN_ID" IS NOT NULL;

我希望此查询能够实现此目标而不会造成歧义。 shit0满足条件并包含所有三个表而没有歧义。 enter image description here

3 个答案:

答案 0 :(得分:0)

您在派生表中使用*并引用列,因此请选中此

SELECT "P_SERIAL_ID" 
FROM (
  SELECT TR."P_SERIAL_ID"
  FROM "B_TRACE"."P_TC_DATA" AS DAT
    FULL OUTER JOIN "B_COLLECTION"."COLLECTION_CONSENT_RC" AS SUBID ON DAT."P_SERIAL_ID" = SUBID."SUBJECT_ID"
    FULL OUTER JOIN "B_TRACE"."P_TC_RC" AS TR ON TR."P_SERIAL_ID" = DAT."P_SERIAL_ID"
  WHERE DAT."STATE_ID" IN ('7','8','9')
) AS SHIT0 
WHERE "SUBJECT_CITIZEN_ID" IS NOT NULL;

答案 1 :(得分:0)

首先,在这种情况下很少需要FULL JOIN

SELECT DAT."P_SERIAL_ID", ?."CONTACT_NOTE"    -- Add the table alias!
FROM "B_TRACE"."P_TC_DATA" DAT LEFT JOIN
     "B_COLLECTION"."COLLECTION_CONSENT_RC" SUBID
     ON DAT."P_SERIAL_ID" = SUBID."SUBJECT_ID" LEFT JOIN
     "B_TRACE"."P_TC_RC" TR
     ON TR."P_SERIAL_ID" = DAT."P_SERIAL_ID"
WHERE DAT."STATE_ID" IN ('7', '8', '9') AND  -- Are these really strings?
      ?."SUBJECT_CITIZEN_ID" IS NOT NULL;    -- Add the table alias!

注意:

  • 不需要子查询。
  • WHERE子句仍然将FULL JOIN变成LEFT JOIN。定义明确的数据模型几乎不需要FULL JOIN
  • 在您的示例中,IN列表是字符串。这些可能是数字,因此您应该删除单引号。
  • 限定 ALL 表名。上面的查询使用?作为表别名的占位符。
  • 摆脱查询中的双引号。它们只会使写作和阅读变得更加困难。
  • 根据SUBJECT_CITIZEN_ID所在的表,所有JOIN可能实际上是INNER JOIN s。

答案 2 :(得分:0)

完全限定您的所有列,甚至考虑重命名它们,以便它们是唯一的:

SELECT dat_serial_id, tr_serial_id, dat_contact_note, tr_contact_note
FROM (
  SELECT 

    "DAT"."P_SERIAL_ID" as dat_serial_id,
    "TR"."P_SERIAL_ID" as tr_serial_id,
    "DAT"."CONTACT_NOTE" as dat_contact_note,
    "TR"."CONTACT_NOTE" as tr_contact_note,
    "SUBID"."SUBJECT_CITIZEN_ID" --guessed at the table


  FROM "B_TRACE"."P_TC_DATA" AS DAT
    FULL OUTER JOIN "B_COLLECTION"."COLLECTION_CONSENT_RC" AS SUBID ON DAT."P_SERIAL_ID" = SUBID."SUBJECT_ID"
    FULL OUTER JOIN "B_TRACE"."P_TC_RC" AS TR ON TR."P_SERIAL_ID" = DAT."P_SERIAL_ID"
  WHERE DAT."STATE_ID" IN ('7','8','9')
) AS SHIT0 
WHERE shit0."SUBJECT_CITIZEN_ID" IS NOT NULL;

请尽可能早地重命名它们,以避免在使用错误的名称时出现陷阱和混乱。如果不需要所有不同的serial_no等,那么只要在内部查询中明确要使用哪一个,就可以在外部查询中继续使用相同的名称进行引用

问题主要是由于SELECT *引起的-避免在顶级查询之外的其他任何条件上使用它进行调试

使用针对任何完全连接表的WHERE子句可将连接减少为左/右连接。如果您在其中的表位于左侧/右侧联接的右侧/左侧,则分别将其拖放到内部联接:

--same as a left join b
SELECT * FROM a FULL JOIN B ON … WHERE a.id = 1

--same as a right join b
SELECT * FROM a FULL JOIN B ON … WHERE b.id = 1

--same as a inner join b
SELECT * FROM a LEFT JOIN B ON … WHERE a.id = 1
SELECT * FROM a RIGHT JOIN B ON … WHERE b.id = 1