【问题标题】:mySQL: query in which all possible values are missing at least oncemySQL:所有可能值至少丢失一次的查询
【发布时间】:2015-09-23 20:20:48
【问题描述】:

我有一个电视节目列表。每个电视节目可能会在 0 个或多个时区被黑屏。说某个节目在某个时区“停电”意味着网络无权在该时区播放该节目。该数据如下所示:

|----|---------------------|
| 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。

例如,在上述数据集中,此假设查询将返回第 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(旁注,我实际上不需要结果中的“限制”列,这只是为了解释的目的)。

【问题讨论】:

  • 非常好的书面问题。但也许下次您也可以尝试提供SqlFiddle,以便我们更快地给您答复
  • 所以你的结果应该包含最少数量的节目?
  • @JuanCarlosOropeza 我想最低限度是 2 个结果。从技术上讲,没有上限,但实际上,结果永远不会超过 10 个。
  • 我不明白你的例子。您说您想获取不受时区限制的节目列表,但您列出的是受限制的节目。
  • @Barmar OP 说in order to supply 2 shows in each timezone that are not blacked out.

标签: mysql sql drupal


【解决方案1】:

创建一个列出所有时区的表。然后,您可以在节目列表中CROSS JOIN 以获取可以显示节目的所有潜在区域。然后使用带有限制表的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

DEMO

这列出了每个时区可以显示的所有节目,而不仅仅是前 2 个。请参阅Using LIMIT within GROUP BY to get N results per group? 了解如何限制每组的结果数量。

【讨论】:

    【解决方案2】:

    考虑到这一点,我很确定我想做的事情是 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

    【讨论】:

    • 那个 SqlFiddle 结果返回 5 显示?所以不明白这是如何解决问题的逻辑
    猜你喜欢
    • 2015-02-19
    • 2016-10-28
    • 2011-04-05
    • 2015-10-13
    • 1970-01-01
    • 2019-07-02
    • 2011-11-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多