[英]How can I join two “unnamed tables/selections” in PostgreSQL?
Given the tables person
and car
and a relationship based on car.id
between the two tables, I could join them using the following code:给定表格
person
和car
以及两个表格之间基于car.id
的关系,我可以使用以下代码加入它们:
SELECT * FROM person
JOIN car
ON person.car_id = car.id;
However, I fail to figure out how to do this if I am working with two unnamed selections.但是,如果我正在使用两个未命名的选择,我无法弄清楚如何做到这一点。 Specifically, I would like to join the below selections based on
id
.具体来说,我想加入以下基于
id
的选择。
SELECT id, phone_number
FROM student
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
UNION
SELECT id, phone_number
FROM administrator
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
SELECT
account_id,
EXTRACT ('day' FROM (NOW()::timestamp - expiry_date::timestamp))
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount)
To clarify, if the first selection would be called table1
and the second selection would be called table2
, I would like to join the selections according to the below code为了澄清,如果第一个选择被称为
table1
而第二个选择被称为table2
,我想根据下面的代码加入选择
SELECT * FROM table1
JOIN table2
ON table1.id = table2.account_id;
You can give them a name each by putting the queries inline:您可以通过将查询内联来给它们一个名称:
SELECT * FROM
(
--begin your first query
SELECT id, phone_number
FROM student
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
UNION
SELECT id, phone_number
FROM administrator
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
--end your first query
) t1
INNER JOIN
(
--begin your second query
SELECT
account_id,
EXTRACT ('day' FROM (NOW()::timestamp - expiry_date::timestamp))
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount)
--end your second query
) t2
ON
t1.id = t2.account_id
You can also turn each query into a named CTE:您还可以将每个查询转换为命名的 CTE:
WITH table1 AS (
SELECT id, phone_number
FROM student
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
UNION
SELECT id, phone_number
FROM administrator
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
),
table2 as (
SELECT
account_id,
EXTRACT ('day' FROM (NOW()::timestamp - expiry_date::timestamp))
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount)
)
--begin the query that joins the CTEs
SELECT * FROM table1
JOIN table2
ON table1.id = table2.account_id;
I'm struck though that you could simplify this query, something like this:尽管您可以简化此查询,但我感到很震惊,如下所示:
SELECT
people.*,
EXTRACT ('day' FROM (NOW()::timestamp - l.expiry_date::timestamp))
FROM
(
SELECT 'student' as typ, id, phone_number FROM student
UNION ALL
SELECT 'admin', id, phone_number FROM administrator
) people
INNER JOIN loan l ON people.id = l.account_id
INNER JOIN fine f ON l.id = f.loan_id
WHERE f.paid_amount < f.fine_amount
You should get into the habit of aliasing everything you put in a query (unless it's a subquery that filters one table only) and then use the aliases:您应该养成为查询中的所有内容设置别名的习惯(除非它是仅过滤一个表的子查询),然后使用别名:
SELECT s.id as studentid, l.id as loanid FROM
student s
INNER JOIN loan l ON s.id = l.account_id
The reasons are many, but by using an alias and fully qualifying all your column references you prevent your query from breaking if someone adds a new column to one of the tables in future, where the name clashes with an existing column.原因有很多,但是通过使用别名并完全限定所有列引用,如果将来有人向其中一个表中添加新列(其中名称与现有列发生冲突),您可以防止查询中断。 By aliasing tables it allows you to join tables in multiple times.
通过给表起别名,它允许您多次连接表。 Example a student has a term_address and a home address:
例如一个学生有一个 term_address 和一个家庭地址:
SELECT * FROM
student s
INNER JOIN address ahome on s.home_address_id = ahome.id
INNER JOIN address aterm on s.term_address_id = aterm.id
This way you don't need a table for term addresses and a table for home addresses - the address table stores all addresses and you alias it differently.这样,您就不需要一个学期地址表和一个家庭地址表 - 地址表存储所有地址并且您使用不同的别名。 A different subset of records participates in each join
不同的记录子集参与每个连接
Anything that represents a block of data can be aliased, be it a table or a subquery, or possibly some other things.任何表示数据块的东西都可以是别名,可以是表或子查询,也可能是其他一些东西。
SELECT * FROM
(subquery here) aliasForSubquery
INNER JOIN
(anther subquery) aliasForANotherSubquery
ON
aliasForSubquery.column = aliasForAnotherSubquery.column
The only thing you don't need to(can't) alias is the subquery that creates your IN(...)
list您唯一不需要(不能)别名的是创建
IN(...)
列表的子查询
with
cte1 as (
SELECT id, phone_number
FROM student
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount))
UNION
SELECT id, phone_number
FROM administrator
WHERE id IN
(SELECT account_id
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount)
),
cte2 as (
SELECT
account_id,
EXTRACT ('day' FROM (NOW()::timestamp - expiry_date::timestamp))
FROM loan
WHERE id IN
(SELECT loan_id
FROM fine
WHERE paid_amount < fine_amount)
)
SELECT *
FROM cte1 JOIN cte2
ON cte1.id = cte2.account_id;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.