【问题标题】:SQL Beginner Query Logic With 3 TablesSQL初学者查询逻辑带3张表
【发布时间】:2015-12-09 19:48:47
【问题描述】:

sql 表如下:likes 列有drinker 和 beer,sells 有 bar 和 beer 列,frequents 有drinker 和 bar 列。

我之前回答过以下说法:

"Drinkers who frequent bars which serve some beer they like"

使用 SQL 查询:

SELECT DISTINCT y.drinker
FROM likes a, sells, frequents y
WHERE a.beer = sells.beer
AND sells.bar = y.bar
AND y.drinker = a.drinker;

现在,我正在尝试修改上面列出的查询以回答类似但不同的陈述:

"Drinkers who only frequent bars which serve beers they like"

从逻辑上讲,修改是只包括那些经常光顾提供他们喜欢的啤酒的酒吧的人,并消除那些光顾不提供他们喜欢的啤酒的酒吧的人。

我最难修改上述查询以满足第二个语句。

我的思考过程可能是进行双重否定,例如:获取以下组中不存在的饮酒者列表:不经常光顾不出售他们喜欢的啤酒的酒吧的饮酒者。但是正确的实现却让我望而却步。

这是我解决此查询的最佳尝试,但我很清楚这是不正确的,因为此查询仍然返回经常光顾某些酒吧(不仅)提供他们喜欢的啤酒的饮酒者:

SELECT distinct x.drinker
FROM frequents x
WHEREexists (SELECT* 
             FROM frequents y, sells z, likes u
             WHERE x.drinker=y.drinker
             AND y.bar = z.bar and z.beer = u.beer
             AND y.drinker = u.drinker);

任何帮助都会很棒,感谢您提供的任何见解。

【问题讨论】:

  • 不确定这是否与课堂练习有关。尽管我可以将其想象为数据库课程的一部分,但我不会将其完全称为初学者问题。我曾与许多难以解决此问题的 SQL 开发人员合作过。

标签: mysql sql querying


【解决方案1】:

我认为这是一个有效的解决方案...

子查询用于过滤掉经常光顾他们喜欢的啤酒数量为 0 的酒吧的饮酒者。

select distinct drinker 
from frequents 
where drinker not in (
    select f.drinker
    from frequents f 
    join sells s on f.bar = s.bar
    left join likes l on l.drinker = f.drinker and l.beer = s.beer
    group by f.drinker, f.bar
    having count(l.drinker) = 0
);

Sample SQL Fiddle

【讨论】:

    【解决方案2】:

    饮酒者经常与他们经常光顾的酒吧数量完全相同,他们出售他们最喜欢的酒吧:

    select drinker
    from frequents
    group by drinker
    having count(bar) = (
        select count(distinct f.bar)
        from
            sells s
            inner join likes l on l.beer = s.beer
            inner join frequents f on f.bar = s.bar and f.drinker = l.drinker
        where f.drinker = frequents.drinker
    )
    

    当您无法匹配所有三个关系三角形时,内部计数会更低。 (请注意啤酒、酒吧和饮料的每个测试如何在内部查询中出现一次。)如果您想查找相反的一组人,您只需将相等性测试更改为大于。

    编辑:

    我正在考虑解决此问题的替代方法。有趣的是,您可能会发现右外连接很有用(而不是连接表周围的括号。)

    frequents 表仍然是下面查询的焦点,逻辑是由找出哪些经常光顾的酒吧也是可以出售喜欢/最爱的酒吧的想法驱动的。由于外部连接,“frequents”一侧永远不会为空,但“likes-sells”一侧只有在无法匹配该频繁的一对时才会有 null。 having 子句中的最后一个测试是多余的,但我想展示能够匹配“频率”两列的计数的对称性,即使只有一个是绝对必要的。

    select f.drinker
    from
        frequents f left outer join (
            likes l inner join sells s on s.beer = l.beer
        ) on f.drinker = l.drinker and f.bar = s.bar
    group by f.drinker
    having count(f.drinker) = count(l.drinker) and count(f.bar) = count(s.bar)
    

    【讨论】:

    • 我在fiddle 上尝试了您的查询,但不知何故,它似​​乎没有提供正确的结果。只有 Fred 和 Sven 应该被列为结果(与 my version 比较)。
    • 是的,我需要完成连接中的圆圈。第二个连接条件是复合的。在我的脑海里,我知道有些东西不见了。
    【解决方案3】:

    我为您构建了一个小fiddle,并提出了您已经提出的建议:一个基于对前往不提供啤酒的地方的饮酒者的否定选择的查询:

    SELECT DISTINCT fdrinker FROM frequents f WHERE NOT EXISTS (
     SELECT 1 FROM frequents WHERE NOT EXISTS
     (SELECT 1 FROM sells WHERE sbar=fbar AND
      sbeer IN (SELECT lbeer FROM likes WHERE ldrinker=fdrinker) )
     AND fdrinker=f.fdrinker )
    

    最里面的子选择列出了特定饮酒者的所有“喜欢”的饮品。如果它销售至少一种喜欢的啤酒,则下一个外部子选择级别将从sells 表中列出该酒吧。下一个级别然后检查经常光顾的酒吧是否存在任何“未能交付”的酒吧。如果没有发生这样的“失败”,顶级选择将向饮酒者展示他们只会经常光顾至少提供一种他们喜欢的啤酒的酒吧。

    【讨论】:

      【解决方案4】:

      例如:

      SELECT a.drinker 
        FROM likes a
        LEFT
        JOIN ( SELECT DISTINCT f.drinker
                          FROM frequents f 
                          LEFT 
                          JOIN sells s 
                            ON s.bar = f.bar 
                          JOIN likes l 
                            ON l.drinker = f.drinker 
                          LEFT 
                          JOIN sells x 
                            ON x.bar = f.bar 
                           AND x.beer = l.beer
                         WHERE x.beer IS NULL
              ) b
           ON b.drinker = a.drinker
        WHERE b.drinker IS NULL;
      

      【讨论】:

        猜你喜欢
        • 2015-12-09
        • 1970-01-01
        • 2014-07-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-28
        • 1970-01-01
        相关资源
        最近更新 更多