假设我有一个包含一定重量水果的篮子清单:
Table baskets
(id, name)
----------------
1, 'apples, oranges and more'
2, 'apples and small oranges'
3, 'apples and bananas'
4, 'only oranges'
5, 'empty'
Table basket_fruits
(id, basket, fruit, weight)
----------------
1, 1, 'apple', 2
2, 1, 'apple', 3
3, 1, 'orange', 2
4, 1, 'banana', 2
5, 2, 'apple', 2
6, 2, 'orange', 1
7, 3, 'apple', 2
8, 3, 'banana', 2
9, 4, 'orange', 2
我很难为这两种情况提出合理有效的查询:
我想获取包含至少一个apple
和至少一个orange
的所有篮子,每个篮子都超过给定的重量。因此weight >= 2
的预期结果是
1, 'apples, oranges and more'
和weight >= 1
1, 'apples, oranges and more'
2, 'apples and small oranges'
我想获取所有包含没有水果超过给定重量的篮子。所以对于weight >= 2
,我希望
5, 'empty'
和weight >= 3
它应该返回
2, 'apples and small oranges'
3, 'apples and bananas'
4, 'only oranges'
5, 'empty'
权重约束只是“每个子关系必须满足某些约束”的占位符。在实践中,我们需要按日期范围,状态等限制子关系,但我不想让这个例子进一步复杂化。
(我正在使用postgresql,以防解决方案需要特定于数据库。)
答案 0 :(得分:1)
我强烈建议您使用group by
和having
来实现此目的。
对于您的第一个问题,此查询应该有效:
SELECT b.name
FROM baskets b INNER JOIN
basket_fruits bf
ON b.id = bf.basket
GROUP BY b.name
HAVING SUM( (bf.fruit = 'apple' AND bf.weight >= 2)::int ) > 0 AND
SUM( (bf.fruit = 'orange' AND bf.weight >= 2)::int ) > 0 ;
第二个稍微复杂一点,因为没有行。但left join
和coalesce()
足以让您以相同的格式表达:
SELECT b.name
FROM baskets b LEFT JOIN
basket_fruits bf
ON b.id = bf.basket
GROUP BY b.name
HAVING SUM( (COALESCE(bf.weight, 0) >= 2)::int ) = 0
答案 1 :(得分:1)
到目前为止,这是我的解决方案:
所有包含水果weight >= 2
的篮子(感谢Gordon Linoff的建议):
SELECT b.* FROM baskets b
INNER JOIN (
SELECT basket FROM basket_fruits
WHERE weight >= 2
GROUP BY basket
HAVING SUM((fruit = 'apple')::int) > 0 AND SUM((fruit = 'orange')::int) > 0
) bf ON b.id = bf.basket
所有没有水果的篮子weight >= 2
:
SELECT b.* FROM baskets b
LEFT JOIN (
SELECT basket, fruit FROM basket_fruits
WHERE weight >= 2
) bf ON b.id = bf.basket
WHERE fruit IS NULL
如果有人有更高效的想法,我很乐意听到他们的意见。
答案 2 :(得分:0)
SELECT b.name
FROM baskets b
INNER JOIN basket_fruits f
ON b.id = f.basket
GROUP BY b.name
HAVING SUM(f.wage) >= 3
OR b.id = 5
这是你所期望的吗?