2011-06-07 49 views
4

我对SQL查询有点麻烦,并且认为我会征求人群的智慧来查看我错过的东西。我很确定下面的工作,但它似乎很差,我想知道是否有一个更聪明的方法(理想情况下使用连接而不是子选择)来做到这一点。所有的行至少有一个孩子都有自己的孩子通过一个条件

的问题

比方说,我有一些表:

Prize 
    - PrizeId 

RulePrize_Map 
    - PrizeId 
    - RuleId 

Rule 
    - RuleId 

Conditional 
    - ConditionalId 
    - RuleId 
    - InputId 
    - ExpectedValue (bit) 

Input 
    - InputId 

一个Prize当至少一个Rule为真赢了。 A Rule全部Conditionals为真时为真。当InputId存在或不存在于Input表中时,Conditional为“真”,如ExpectedValue指定的字段。这也许可以等同于:Count(InputId in Input table) = ExpectedValue对于Conditional'sInputId

一些例子:

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是 “真”。我会解决:“所有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

只是一个想法:也许看不包括奖金,所有的规则都是假的... – pascal 2011-06-07 12:39:16

回答

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

这确实‘其中的任何规则是真实的。’如果你想‘所有的规则都是真实的’,然后请从主查询的SELECT和GROUP BY的“PrizeRule_Map.RuleId”线(然后你也不需要包装查询) – MatBailie 2011-06-07 12:46:15

+0

真棒,很肯定这是完美的 - 将迎来所接受适当一旦确认 – 2011-06-07 12:47:57

+0

。非常感谢了“大奖”更新按照问题变化 – 2011-06-07 12:58:08

-2

尝试以下操作:

SELECT Rule.RuleId, Rule.RuleName 
FROM Rule 
INNER JOIN Conditional ON Rule.RuleId = Conditional.RuleId 
Where Conditional.ExpectedValue == true 
+1

您查询不考虑与规则相关的“全部”条件,甚至不会查看“输入”的内容。 – pascal 2011-06-07 12:35:09

+0

这将显示所有规则,只有一个条件为真。它也不会正确地评估条件(ExpectedValue == true不会使条件成为必需条件,相反,如果输入表包含条件的InputId,则表示条件为真)。 – 2011-06-07 12:35:21

+1

这不处理expectedVluae = false,并且在输入表 – 2011-06-07 12:36:45

1

要获得全部RuleId s所有条件均为真:

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但使用两个JOIN S,其中只有一个区别(EXCEPTGROUP 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 
+0

您使用了'COUNT(NULL | 1)'我在哪里使用了'SUM(0 | 1)',你是否意识到这种性能差异? – MatBailie 2011-06-07 13:28:23

+0

需要在布尔逻辑中指定'i.InputId'或'c.InputId'? – MatBailie 2011-06-07 13:31:05

+0

@Dems:你说得对'i.InputId'是必要的。 – 2011-06-07 13:32:33

相关问题