我对SQL查询有点麻烦,并且认为我会征求人群的智慧,看看我缺少什么。我很确定下面有效,但看起来真的很差,我想知道是否有更聪明的方法(理想情况下使用连接而不是子选择)来做到这一点。
问题
假设我有一些表格:
Prize
- PrizeId
RulePrize_Map
- PrizeId
- RuleId
Rule
- RuleId
Conditional
- ConditionalId
- RuleId
- InputId
- ExpectedValue (bit)
Input
- InputId
当至少有一个Prize
为真时赢得Rule
。当Rule
的所有为真时,Conditionals
为真。当Conditional
在InputId
表中存在或不存在时,Input
为“真”,由ExpectedValue
字段指定。对于Count(InputId in Input table)
ExpectedValue
,这可能被视为等同于:Conditional's
= InputId
。
一些例子:
Conditional (InputId = 11, ExpectedValue = 1) -> True if InputId 11 in Input Table
Conditional (InputId = 12, ExpectedValue = 0) -> True if Inputid 12 NOT in Input Table
我的目标
我想让所有Prizes
至少有一个Rule
为“true”。我愿意接受:“所有Rules
都是真的”。
我的尝试
select p.PrizeId from Prize p INNER JOIN RulePrize_Map rpm ON rpm.PrizeId = p.PrizeId
WHERE p.PrizeId IN
(select r.PrizeId from Rule r
where
(select count(*) from Conditional c1 where c1.RuleId = r.RuleId)
=
(select count(*) from Conditional c2
where c2.RuleId = r.RuleId AND
(select count(*) from Input i where i.InputId = c2.InputId) = c2.ExpectedValue
)
)
GROUP BY p.prizeId
答案 0 :(得分:4)
问题有所改变,所以我重新回答了问题......
SELECT
PrizeId
FROM
(
SELECT
PrizeRule_Map.PrizeId,
PrizeRule_Map.RuleId
FROM
PrizeRule_Map
INNER JOIN
Rule
ON Rule.RuleId = PrizeRule_Map.RuleId
INNER JOIN
Conditional
ON Conditional.RuleId = Rule.RuleID
LEFT JOIN
Input
ON Input.InputId = Conditional.InputID
GROUP BY
PrizeRule_Map.PrizeId,
PrizeRule_Map.RuleId
HAVING
COUNT(*) = SUM(CASE Conditional.ExpectedValue
WHEN 1 THEN CASE WHEN Input.InputId IS NULL THEN 0 ELSE 1 END
WHEN 0 THEN CASE WHEN Input.InputId IS NULL THEN 1 ELSE 0 END
END
)
)
AS map
GROUP BY
PrizeId
答案 1 :(得分:1)
获取ALL条件为真的所有RuleId
:
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
LEFT JOIN Input i
ON i.InputId = c.InputId
GROUP BY r.RuleID
HAVING COUNT( CASE WHEN (c.ExpectedValue=1) AND (i.InputId IS NOT NULL)
OR (c.ExpectedValue=0) AND (i.InputId IS NULL)
THEN 1
ELSE NULL
END )
= COUNT( * )
另一种方式 - 可能更慢,但测试速度并没有坏处。它不使用CASE
,而是两个EXCEPT
的差异(JOIN
),其中只有一个使用GROUP BY
:
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
LEFT JOIN Input i
ON i.InputId = c.InputId
WHERE c.ExpectedValue = 1
GROUP BY r.RuleID
HAVING COUNT( i.InputId ) = COUNT( * )
EXCEPT
SELECT r.RuleID
FROM Rule r
JOIN Conditional c
ON c.RuleId = r.RuleId
JOIN Input i
ON i.InputId = c.InputId
WHERE c.ExpectedValue = 0
答案 2 :(得分:-2)
尝试以下方法:
SELECT Rule.RuleId, Rule.RuleName
FROM Rule
INNER JOIN Conditional ON Rule.RuleId = Conditional.RuleId
Where Conditional.ExpectedValue == true