具有3个表的SQL初学者查询逻辑

时间:2015-09-13 20:17:11

标签: mysql sql querying

sql表如下:喜欢列饮酒和啤酒,卖柱栏和啤酒,经常与列饮酒者和酒吧。

我之前已经回答了以下声明:

"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);

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

4 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

我为你建了一个小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表中列出此栏。然后上一级检查经常出现的条形图,以防止任何条形图未能交付"。如果没有这样的"失败"发生顶级选择将呈现饮用者,只有频繁的酒吧,其中至少有一个他们喜欢的啤酒供应。

答案 2 :(得分:0)

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

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表仍然是下面查询的焦点,逻辑是由找出哪些常去的酒吧也是可以出售喜欢/喜欢的酒吧的想法驱动的。由于外连接,“频率”方面永远不会为空,但只有当一对不能匹配时,“喜欢卖”方才会有空值。 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)

答案 3 :(得分:0)

E.g:

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;