mySQL: 所有可能值至少丢失一次的查询
mySQL: query in which all possible values are missing at least once
我有一份电视节目清单。每个电视节目可能会在 0 个或多个时区被中断。说一个节目在某个时区是 "blacked out" 意味着该网络无权在该时区播放该节目。此数据如下所示:
|----|---------------------|
| ID | Show |
|----|---------------------|
| 1 | Nightly News |
| 2 | Primetime Sitcom |
| 3 | Daytime Talkshow |
| 4 | Nightly News II |
| 5 | Daytime Talkshow II |
| 6 | Nightly News III |
|----|---------------------|
|
|-----join
|
v
|----|----------------------|
| ID | Timezone Restriction |
|----|----------------------|
| 1 | EST |
| 1 | CST |
| 1 | PST |
| 2 | EST |
| 2 | CST |
| 3 | PST |
| 5 | CST |
| 5 | PST |
| 6 | HST |
|----|----------------------|
并非所有节目都受时区限制(大多数没有)。鉴于这些数据,我需要获取一个包含尽可能多的结果的列表,以便在每个时区提供 2 个未停播的节目。结果应按 ID 排序,每个时区看到尽可能少的不受限制的 ID。
例如,在上面的数据集中,这个假设的查询将 return 行 1-4,例如:
|----|------------------|--------------|
| ID | Show | Restrictions |
|----|------------------|--------------|
| 1 | Nightly News | EST,CST,PST |
| 2 | Primetime Sitcom | EST,CST |
| 3 | Daytime Talkshow | PST |
| 4 | Nightly News II | None |
|----|------------------|--------------|
如您所见,在上面的结果集中,所有时区至少有2个不受限制的节目。 EST 或 CST 的观众可以观看节目 3 和 4。PST 的观众可以观看节目 2 和 4。MST 或 HST 的观众可以观看节目 1 和 2。
我一辈子都想不出 SQL 来解决这个问题(旁注,我实际上不需要结果中的 "restrictions" 列,那只是此处用于说明目的)。
创建一个列出所有时区的 table。然后,您可以 CROSS JOIN
将其与节目列表一起使用,以获取可以显示节目的所有潜在区域。然后使用带有限制 table 的 LEFT JOIN
来过滤掉符合任何限制的行,如 Return row only if value doesn't exist.
中所述
SELECT s.show, z.zone
FROM shows AS s
CROSS JOIN timezones AS z
LEFT JOIN restrictions AS r ON r.id = s.id AND r.`Timezone Restriction` = z.zone
WHERE r.id IS NULL
ORDER BY z.zone, s.id
这列出了每个时区可以显示的所有节目,而不仅仅是前 2 个。请参阅 Using LIMIT within GROUP BY to get N results per group? 了解如何限制每组的结果数量。
所以再考虑一下,我很确定我想做的事情是 1) 查找每个时区的不受限制的节目列表,以及 2) UNION
将它们全部放在一起。这实际上看起来几乎完全是我现在想到的用例 UNION
创建的。
所以我可以像这样不受限制地观看单个时区的节目:
SELECT `shows`.`ID`
FROM shows
LEFT JOIN restrictions
ON `shows`.`ID`=`restrictions`.`ID`
AND `shows`.`ID` NOT IN (
SELECT `restrictions`.`ID`
FROM restrictions
WHERE `Timezone Restriction`='EST'
)
LIMIT 2
然后像这样将它们链接在一起:
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='EST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='CST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='MST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='PST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='HST') LIMIT 2)
ORDER BY ID;
建立在 @Barmar 提供的 sqlfiddle 之上:http://www.sqlfiddle.com/#!9/25773/1/0
我有一份电视节目清单。每个电视节目可能会在 0 个或多个时区被中断。说一个节目在某个时区是 "blacked out" 意味着该网络无权在该时区播放该节目。此数据如下所示:
|----|---------------------|
| ID | Show |
|----|---------------------|
| 1 | Nightly News |
| 2 | Primetime Sitcom |
| 3 | Daytime Talkshow |
| 4 | Nightly News II |
| 5 | Daytime Talkshow II |
| 6 | Nightly News III |
|----|---------------------|
|
|-----join
|
v
|----|----------------------|
| ID | Timezone Restriction |
|----|----------------------|
| 1 | EST |
| 1 | CST |
| 1 | PST |
| 2 | EST |
| 2 | CST |
| 3 | PST |
| 5 | CST |
| 5 | PST |
| 6 | HST |
|----|----------------------|
并非所有节目都受时区限制(大多数没有)。鉴于这些数据,我需要获取一个包含尽可能多的结果的列表,以便在每个时区提供 2 个未停播的节目。结果应按 ID 排序,每个时区看到尽可能少的不受限制的 ID。
例如,在上面的数据集中,这个假设的查询将 return 行 1-4,例如:
|----|------------------|--------------|
| ID | Show | Restrictions |
|----|------------------|--------------|
| 1 | Nightly News | EST,CST,PST |
| 2 | Primetime Sitcom | EST,CST |
| 3 | Daytime Talkshow | PST |
| 4 | Nightly News II | None |
|----|------------------|--------------|
如您所见,在上面的结果集中,所有时区至少有2个不受限制的节目。 EST 或 CST 的观众可以观看节目 3 和 4。PST 的观众可以观看节目 2 和 4。MST 或 HST 的观众可以观看节目 1 和 2。
我一辈子都想不出 SQL 来解决这个问题(旁注,我实际上不需要结果中的 "restrictions" 列,那只是此处用于说明目的)。
创建一个列出所有时区的 table。然后,您可以 CROSS JOIN
将其与节目列表一起使用,以获取可以显示节目的所有潜在区域。然后使用带有限制 table 的 LEFT JOIN
来过滤掉符合任何限制的行,如 Return row only if value doesn't exist.
SELECT s.show, z.zone
FROM shows AS s
CROSS JOIN timezones AS z
LEFT JOIN restrictions AS r ON r.id = s.id AND r.`Timezone Restriction` = z.zone
WHERE r.id IS NULL
ORDER BY z.zone, s.id
这列出了每个时区可以显示的所有节目,而不仅仅是前 2 个。请参阅 Using LIMIT within GROUP BY to get N results per group? 了解如何限制每组的结果数量。
所以再考虑一下,我很确定我想做的事情是 1) 查找每个时区的不受限制的节目列表,以及 2) UNION
将它们全部放在一起。这实际上看起来几乎完全是我现在想到的用例 UNION
创建的。
所以我可以像这样不受限制地观看单个时区的节目:
SELECT `shows`.`ID`
FROM shows
LEFT JOIN restrictions
ON `shows`.`ID`=`restrictions`.`ID`
AND `shows`.`ID` NOT IN (
SELECT `restrictions`.`ID`
FROM restrictions
WHERE `Timezone Restriction`='EST'
)
LIMIT 2
然后像这样将它们链接在一起:
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='EST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='CST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='MST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='PST') LIMIT 2)
UNION
(SELECT `shows`.`ID` FROM shows LEFT JOIN restrictions ON `shows`.`ID`=`restrictions`.`ID` AND `shows`.`ID` NOT IN (select `restrictions`.`ID` from restrictions where `Timezone Restriction`='HST') LIMIT 2)
ORDER BY ID;
建立在 @Barmar 提供的 sqlfiddle 之上:http://www.sqlfiddle.com/#!9/25773/1/0