使用Postgres进行“多次”搜索

时间:2018-05-21 13:29:58

标签: sql postgresql

基本上,我试图从一个表中获取一个值,然后在另外三个表中搜索该值。但我想在一个查询中完成所有这些。

select user_id from users where email = 'bob@example.com

该搜索的值需要进入如下查询:

SELECT *
FROM table1
JOIN table2 ON (table1.user_id = 
table2.user_id)
WHERE table1.user_id  =  <<<THE RESULTS FROM THE FIRST QUERY>>>
OR table2.user_id = <<<THE RESULTS FROM THE FIRST QUERY>>>

如果user_id不在第一个表中,那么这个JOIN仍然有用吗?

1 个答案:

答案 0 :(得分:1)

CTE - Common Table Expression(AFAIK始终在Postgres中实现)将作为第一个查询的占位符,然后您可以使用它来加入其他表。此外,UNION听起来像您想要的OR样式查找一个或多个表t1 .. t3中的匹配数据,例如:

WITH cteUsers AS
(
    select user_id from users where email = 'bob@example.com'
)
SELECT t1.user_id, t1.othercol, ...
FROM table1 t1 INNER JOIN cteUsers cte on t1.user_id = cte.user_id
UNION
SELECT t2.user_id, t2.othercol, ...
FROM table1 t2 INNER JOIN cteUsers cte on t2.user_id = cte.user_id
UNION
SELECT t3.user_id, t3.othercol, ...
FROM table1 t3 INNER JOIN cteUsers cte on t3.user_id = cte.user_id;

附注:

  • 各个表othercolt1..t3列中返回的数字和类型必须匹配。
  • 如果同一个用户在具有相同othercol值的多个表中匹配,则UNION将具有删除重复项的效果(类似于DISTINCT)。如果您想要重复的行,请将其替换为UNION ALL
  • 如果多个表t1 .. t3成功将连接匹配到users,那么每个匹配的表将返回一行(除非它被不同的表删除,如上所述)
  • 如果表1,表2或表3中没有匹配项,则查询将不返回任何内容。如果您想要从users返回单行而不管匹配(with nulls for unmatched columns),那么用户与至少一个表t1..t3之间需要LEFT JOIN

编辑 - 回复:确保users行始终返回至少一条记录/表明哪些表匹配

如上所述,您可以使用LEFT OUTER JOIN来处理3个表中任何一个都没有匹配的情况。在这里,我将3个表匹配的输出汇总到另一个CTE中,然后在CTE之间做一个最终的LOJ,用coalesce突出显示连接失败的位置(你可以显然也会留下null,如果需要的话:

WITH cteUsers AS
(
    -- Replace with bob to see a match in 2 tables
    -- Replace with fred to see a match in 1 table.
    select user_id from users where email = 'missing@example.com' 
),
cteTables AS
(
  SELECT t1.user_id, 'MatchedTable1' as match, t1.othercol
  FROM table1 t1 INNER JOIN cteUsers cte on t1.user_id = cte.user_id
  UNION
  SELECT t2.user_id, 'MatchedTable2' as match, t2.othercol
  FROM table2 t2 INNER JOIN cteUsers cte on t2.user_id = cte.user_id
  UNION
  SELECT t3.user_id, 'MatchedTable3' as match, t3.othercol
  FROM table3 t3 INNER JOIN cteUsers cte on t3.user_id = cte.user_id
)
SELECT u.user_id, coalesce(match, 'Not Matched At All') as matched, t.othercol
FROM cteUsers u LEFT OUTER JOIN cteTables t ON u.user_id = t.user_id;

我已经放了一个SqlFiddle up here,希望能够解决问题吗?

相关问题