这是对question I posted last week。
的跟进上一个问题的摘要:
我想加入两个表格,然后选择拥有booking_code
或parent_booking_code
的人并显示结果。
在我们的代码中多次尝试实现答案后,我们发现我们还希望优先考虑booking_code
人。也就是说,如果我们有下表和数据('kelvin'和'michael'的条目与之前不同):
保留
booking_code | description
-------------+-------------
alpha | alpha code
beta | beta code
gamma | gamma code
omega | omega code
来宾(注意:-
表示NULL
)
name | booking_code | parent_booking_code
------------+----------------+----------------------
andrew | alpha | -
kelvin | - | beta ***
michael | beta | - ***
nancy | - | beta
olaf | gamma | -
patricia | - | gamma
quincy | - | omega
raphael | kappa | -
stanley | - | kappa
timmy | - | delta
预期输出: 我们希望查询给我们:
name | code
----------+-------
andrew | alpha
michael | beta
olaf | gamma
quincy | omega
Previous solution会为代码kelvin
指定名称beta
,因为我们正在挑选具有“最小”名称的人。
这是我们尝试过的一件事,它没有给我们andrew - alpha
:
SELECT
g.name,
reservations.booking_code AS code
FROM
(
SELECT *, booking_code AS bc
FROM guests AS g1
WHERE booking_code IN
(SELECT DISTINCT parent_booking_code FROM guests WHERE parent_booking_code IS NOT NULL)
UNION
SELECT *, parent_booking_code AS bc
FROM guests AS g2
WHERE parent_booking_code NOT IN (SELECT booking_code FROM guests WHERE booking_code IS NOT NULL)
) AS g
JOIN
reservations ON
g.bc = reservations.booking_code ;
/*
name | code
---------+-------
olaf | gamma
quincy | omega
michael | beta
(3 rows)
*/
可能是因为我们没有对UNION
的记录booking_code
而没有相应的parent_booking_code
。但是,我们认为如果我们添加它,UNION
会很大,而且会很慢。
我们也试过这个,但无法弄清楚如何通过不同的代码过滤记录:
SELECT
guests.name AS name,
guests.combo_code AS code,
MIN(guests.ranking) AS rank
FROM
reservations
JOIN
(SELECT
COALESCE (booking_code, parent_booking_code) AS combo_code,
CASE WHEN booking_code IS NOT NULL THEN 1
ELSE 2
END AS ranking,
guests.*
FROM guests
) AS guests ON
guests.combo_code = reservations.booking_code
GROUP BY name, code
ORDER BY rank, name;
/*
name | code | rank
----------+-------+------
andrew | alpha | 1
michael | beta | 1
olaf | gamma | 1
kelvin | beta | 2
nancy | beta | 2
patricia | gamma | 2
quincy | omega | 2
(7 rows)
*/
用于创建表和数据的SQL查询:
CREATE TABLE reservations (
booking_code VARCHAR(15),
description VARCHAR(15)
);
INSERT INTO reservations VALUES
('alpha', 'alpha code'), ('beta', 'beta code'), ('gamma', 'gamma code'), ('omega', 'omega code') ;
CREATE TABLE guests (
name VARCHAR(20),
booking_code VARCHAR(15),
parent_booking_code VARCHAR(15)
);
INSERT INTO guests VALUES
('andrew', 'alpha', NULL), ('kelvin', NULL, 'beta'), ('michael', 'beta', NULL), ('nancy', NULL, 'beta'),
('olaf', 'gamma', NULL), ('patricia', NULL, 'gamma'), ('quincy', NULL, 'omega'), ('raphael', 'kappa', NULL),
('stanley', NULL, 'kappa'), ('timmy', NULL, 'delta') ;
答案 0 :(得分:1)
试试这个
with cte as (
SELECT
guests.name AS name,
guests.combo_code AS code,
MIN(guests.ranking) AS rank
FROM
reservations
JOIN
(SELECT
COALESCE (booking_code, parent_booking_code) AS combo_code,
CASE WHEN booking_code IS NOT NULL THEN 1
ELSE 2
END AS ranking,
guests.*
FROM guests
) AS guests ON
guests.combo_code = reservations.booking_code
GROUP BY name, code
ORDER BY rank, name
) , cte2 as (
select code,min(rank) as rank from cte group by code
)
select name,cte.code,cte.rank from cte inner join cte2 on cte.rank=cte2.rank where
cte.rank=cte2.rank and cte.code=cte2.code
答案 1 :(得分:0)
让我们从上一个问题中提供的解决方案中删除GROUP BY,ORDER BY和聚合,并在投影中添加一个额外的字段,告诉我们用户是否实际具有hi-priority booking_code。
SELECT
guests.name AS name,
reservations.booking_code AS code,
COALESCE(reservations.booking_code = guests.booking_code, 0) AS has_good
FROM
reservations
JOIN
guests ON
reservations.booking_code = guests.booking_code OR
reservations.booking_code = guests.parent_booking_code
COALESCE就在这里,如果guests.booking_code为NULL,则表达式的结果为0而不是NULL。在您的DBMS中,COALESCE可能被称为ISNULL或IFNULL。
现在让我们将它编组为BY代码,然后选择max(has_good)。我们不选择客人名称,因为我们还不需要它。它给我们的是,我们现在知道每个代码是否有该代码的高pri用户:
SELECT
reservations.booking_code AS code,
MAX(COALESCE(reservations.booking_code = guests.booking_code, 0)) AS has_good
FROM
reservations
JOIN
guests ON
reservations.booking_code = guests.booking_code OR
reservations.booking_code = guests.parent_booking_code
GROUP BY code;
有了这些信息,我们现在可以稍微更改原始查询,这样如果有一位客人对给定代码进行了高价预订,我们会选择这样的客人,否则我们会选择任何一位客人:< / p>
SELECT
MIN(guests.name) AS name,
reservations.booking_code AS code
FROM
reservations
JOIN
guests ON
reservations.booking_code = guests.booking_code OR
reservations.booking_code = guests.parent_booking_code
JOIN (
SELECT
reservations.booking_code AS code,
MAX(COALESCE(reservations.booking_code = guests.booking_code, 0)) AS has_good
FROM
reservations
JOIN
guests ON
reservations.booking_code = guests.booking_code OR
reservations.booking_code = guests.parent_booking_code
GROUP BY code
) AS availability ON availability.code = reservations.booking_code
WHERE availability.has_good = COALESCE(reservations.booking_code = guests.booking_code, 0)
GROUP BY code;
请注意,此查询只是您上一个问题的查询,并且是针对我们上面构建的子查询加入的。然后它会过滤掉没有高优先级预订代码的用户,如果已知代码至少有一个用户拥有该代码。
我在你的样本数据集上测试了它,我相信它应该适用于一般情况。
编辑:作者在评论中询问是否可以删除JOIN中的一个预订表。确实,这是一个稍微修改过的查询,只能从预订中选择一次:
SELECT
MIN(guests.name) AS name,
availability.code AS code
FROM
(
SELECT
reservations.booking_code AS code,
MAX(COALESCE(reservations.booking_code = guests.booking_code, 0)) AS has_good
FROM
reservations
JOIN
guests ON
reservations.booking_code = guests.booking_code OR
reservations.booking_code = guests.parent_booking_code
GROUP BY code
) AS availability
JOIN
guests ON
availability.code = guests.booking_code OR
availability.code = guests.parent_booking_code
WHERE availability.has_good = COALESCE(availability.code = guests.booking_code, 0)
GROUP BY code;