如何扩展此查询以查找三个项目的有效组合?

时间:2011-12-14 20:42:55

标签: sql tsql

我完全不希望在这里得到任何答案,但无论如何我都会尝试。

所以这出演了天际。我想要一种简单的方法来查找哪些成分可以组合成不同的药水/毒药,所以我制作了一个有ID和名字的成分表;具有ID,名称,毒药标志和药水标志的效果表(药水和毒药是互斥的);以及具有成分ID和效果ID的连接表。

所以它的工作方式是每种成分都有4种不同的效果,对多种成分重复效果。在游戏中你可以组合2或3种成分,结果是一种药水或毒药,所有的效果都与至少2种成分相匹配。因此,如果您使用3种成分并且effect1同时出现在ingredient1和ingredient2上,而effect2同时出现在ingredient1和ingredient3上,那么结果将是一种具有effect1和effect2的药水/毒药。

我能够自己提出一个查询,它将显示每种可能的2种成分组合,它们会产生一种没有毒害效果的药水。首先,我需要找到每种可能的2种成分组合,它们只具有非毒性的匹配效果:

SELECT i1.UniqIngredient UniqIngredient1, i2.UniqIngredient UniqIngredient2
FROM Ingredient i1
CROSS JOIN Ingredient i2
INNER JOIN IngredientEffectJT jt1 ON i1.UniqIngredient = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON i2.UniqIngredient = jt2.UniqIngredient
INNER JOIN Effect e ON jt1.UniqEffect = e.UniqEffect AND jt2.UniqEffect = e.UniqEffect
WHERE i1.UniqIngredient < i2.UniqIngredient
GROUP BY i1.UniqIngredient, i2.UniqIngredient
HAVING SUM(e.Poison) = 0

成分与成分交叉连接以获得每种组合,但由于成分的顺序无关紧要,我最终会得到两倍的结果。这就是为什么WHERE检查i1.UniqIngredient&lt; i2.UniqIngredient。我只会看到每种组合一次,2种成分的较低ID将始终位于第1列。 我将两种成分加入到相同的效果中,因为我只关心产生结果的组合。 然后我用2种成分对它们进行分组并计算它们分享的毒药效果,因为我只想要有0种毒药效果的组合。

然后我将这个结果用作一个表格,我将其加入到成分和效果表中,以获得生成药水的每种可能的2种成分组合的列表,以及每种组合的效果:

SELECT i1.Name, i2.Name, e.Name
FROM (SELECT i1.UniqIngredient UniqIngredient1, i2.UniqIngredient UniqIngredient2
FROM Ingredient i1
CROSS JOIN Ingredient i2
INNER JOIN IngredientEffectJT jt1 ON i1.UniqIngredient = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON i2.UniqIngredient = jt2.UniqIngredient
INNER JOIN Effect e ON jt1.UniqEffect = e.UniqEffect AND jt2.UniqEffect = e.UniqEffect
WHERE i1.UniqIngredient < i2.UniqIngredient
GROUP BY i1.UniqIngredient, i2.UniqIngredient
HAVING SUM(e.Poison) = 0) il
INNER JOIN Ingredient i1 ON il.UniqIngredient1 = i1.UniqIngredient
INNER JOIN Ingredient i2 ON il.UniqIngredient2 = i2.UniqIngredient
INNER JOIN IngredientEffectJT jt1 ON i1.UniqIngredient = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON i2.UniqIngredient = jt2.UniqIngredient
INNER JOIN Effect e ON jt1.UniqEffect = e.UniqEffect AND jt2.UniqEffect = e.UniqEffect
ORDER BY i1.Name, i2.Name, e.Name

使用相同的查询我只需更改HAVING行来检查e.Potion而不是e.Poison,就可以找到2种没有药水效果的成分毒药组合。

这一切都很好,但是当我想介绍它变得棘手的第三种成分时。我很难过。我可以修改这个查询以检查所有具有相同效果的3种成分,但这不是我想要的。我想找到第3种成分,它与1种成分具有不同的效果。

任何帮助?


修改


更新:所以经过几个小时的努力,我想出了一个大的,丑陋的,缓慢的,难以理解的查询(我实际上甚至不记得为什么我必须在效果表上做那个疯狂的连接条件。但是当我改变它时,整个查询速度慢了2倍,所以它实际上比我拥有它的速度更快,虽然我不知道为什么......),几乎做我想要的。除非有人有任何其他想法或看到改进我的新查询的方法,否则这可能会尽可能接近。

SELECT DISTINCT il.Name1, il.Name2, il.Name3, e.Name
FROM
(SELECT DISTINCT i1.UniqIngredient Ingredient1, i1.Name Name1, i2.UniqIngredient Ingredient2, i2.Name Name2, i3.UniqIngredient Ingredient3, i3.Name Name3
FROM Ingredient i1
INNER JOIN Ingredient i2 ON i1.UniqIngredient < i2.UniqIngredient
INNER JOIN Ingredient i3 ON i2.UniqIngredient < i3.UniqIngredient
INNER JOIN IngredientEffectJT jt1 ON i1.UniqIngredient = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON i2.UniqIngredient = jt2.UniqIngredient
INNER JOIN IngredientEffectJT jt3 ON i3.UniqIngredient = jt3.UniqIngredient
INNER JOIN Effect e ON (jt1.UniqEffect = e.UniqEffect AND (jt2.UniqEffect = e.UniqEffect OR jt3.UniqEffect = e.UniqEffect)) OR (jt2.UniqEffect = e.UniqEffect AND jt3.UniqEffect = e.UniqEffect)
WHERE (EXISTS (SELECT 1
               FROM IngredientEffectJT jt1
               INNER JOIN IngredientEffectJT jt2 ON jt1.UniqEffect = jt2.UniqEffect
               WHERE jt1.UniqIngredient = i1.UniqIngredient 
               AND jt2.UniqIngredient = i2.UniqIngredient)
       AND (EXISTS (SELECT 1
                    FROM IngredientEffectJT jt1
                    INNER JOIN IngredientEffectJT jt3 ON jt1.UniqEffect = jt3.UniqEffect
                    WHERE jt1.UniqIngredient = i1.UniqIngredient 
                    AND jt3.UniqIngredient = i3.UniqIngredient)
         OR EXISTS (SELECT 1
                    FROM IngredientEffectJT jt2
                    INNER JOIN IngredientEffectJT jt3 ON jt2.UniqEffect = jt3.UniqEffect
                    WHERE jt2.UniqIngredient = i2.UniqIngredient 
                    AND jt3.UniqIngredient = i3.UniqIngredient)))
       OR (EXISTS (SELECT 1
                  FROM IngredientEffectJT jt1
                  INNER JOIN IngredientEffectJT jt3 ON jt1.UniqEffect = jt3.UniqEffect
                  WHERE jt1.UniqIngredient = i1.UniqIngredient 
                  AND jt3.UniqIngredient = i3.UniqIngredient)
      AND EXISTS (SELECT 1
                  FROM IngredientEffectJT jt2
                  INNER JOIN IngredientEffectJT jt3 ON jt2.UniqEffect = jt3.UniqEffect
                  WHERE jt2.UniqIngredient = i2.UniqIngredient 
                  AND jt3.UniqIngredient = i3.UniqIngredient))
GROUP BY i1.UniqIngredient, i1.Name, i2.UniqIngredient, i2.Name, i3.UniqIngredient, i3.Name
HAVING SUM(e.Poison) = 0) il
INNER JOIN IngredientEffectJT jt1 ON il.Ingredient1 = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON il.Ingredient2 = jt2.UniqIngredient
INNER JOIN IngredientEffectJT jt3 ON il.Ingredient3 = jt3.UniqIngredient
INNER JOIN Effect e ON (jt1.UniqEffect = e.UniqEffect AND (jt2.UniqEffect = e.UniqEffect OR jt3.UniqEffect = e.UniqEffect)) OR (jt2.UniqEffect = e.UniqEffect AND jt3.UniqEffect = e.UniqEffect)
ORDER BY il.Name1, il.Name2, il.Name3, e.Name

在内部查询中:

FROM Ingredient i1
INNER JOIN Ingredient i2 ON i1.UniqIngredient < i2.UniqIngredient
INNER JOIN Ingredient i3 ON i2.UniqIngredient < i3.UniqIngredient

这创造了3种成分的每种可能组合,其中顺序无关紧要,没有重复。然后加入到IngredientEffectJT和Effect ......我实际上不记得效果的疯狂加入是什么。看一下,我认为确保至少有两种成分存在效果,但这就是WHERE子句正在做的事情。并且简化效果连接会导致它运行得更慢,所以......无论如何。

那么GROUP BY就在那里,所以我可以计算匹配毒药效果的数量。因为我不得不按照3种成分进行分组,所以我失去了单独的匹配效果,所以我需要将所有这些成分重新加入到它们的效果中并找到匹配的效果。

此查询的问题在于它将显示所有3种成分具有相同效果的组合。这些组合毫无意义,因为你可以通过仅使用其中的2个来做同样的事情,这样就有点浪费了。

所以,这是我能想到的最好的。它真的很慢,所以也许我会把它保存到一个新表中,以便将来再次查询更容易,更快。

6 个答案:

答案 0 :(得分:5)

试试这个

declare @combos table (comboId int identity, ingredient1 int, ingredient2 int, ingredient3 int null)

--create table of all unique 2 and 3 ingredient combinations (unique potions)
insert int @combos (ingredient1, ingredient2, ingredient3)
select 
    distinct
    i1.ID,
    i2.ID,
    i3.ID
from
    ingredient i1
    inner join ingredient i2 on i1.ID < i2.ID
    left outer join ingredient i3 on i2.ID < i3.ID

--create table to hold mapping between unique combinations and ingredients
declare @combo_ingredient table (ComboId int, IngredientId int)

--insert into the mapping table
insert into @combo_ingredient (ComboId, IngredientId)
select ID, ingredient1 from @combos

insert into @combo_ingredient (ComboId, IngredientId)
select ID, ingredient1 from @combos

insert into @combo_ingredient (ComboId, IngredientId)
select ID, ingredient3 from @combos where ingredient3 is not null

--create table to hold mapping between unique combinations (potions) and the effects it will have
declare @combo_effect (comboId int, effectId int)

insert into @combo_effect (comboId, effectId)
select 
    c.ComboId, ec.EffectId
from
    @combo_ingredient c
    inner join effect_ingredient ec on c.IngredientId = ec.IngredientId
having
    count(*) > 1
group by 
    c.comboId, ec.EffectId

--remove combinations that include an ingredient that do not contribute to an effect
delete from @combo_effect ce
where ce.ComboId in (
    select 
        ci.ComboId 
    from 
        @combo_ingredient ci
        inner join effect_ingredient ei on ci.IngredientId = ei.IngredientId
        left outer join @combo_effect ce on ce.ComboId = ci.ComboId and ce.EffectId = ei.EffectId
    where 
        ce.ComboId is null
)

--you can then query combo_effect for whatever information you want
--all combos with no poison effects
select comboId from 
    @combo_effect ce 
    left outer join effect e on ce.effectId = e.effectId and e.PoisonFlag = 1
group by 
    comboId
having 
    Count(e.id) = 0

答案 1 :(得分:2)

不确定这会如何表现,但我认为它更简单:

select
          (select Name from Ingredient where ID = e1.UniqIngredient) as Ingredient1,
          (select Name from Ingredient where ID = jt1.UniqIngredient) as Ingredient2,
          (select Name from Ingredient where ID = jt2.UniqIngredient) as Ingredient3,
          ee1.Name as Effect1,
          ee2.Name as Effect2
   from IngredientEffectJT e1
       inner join IngredientEffectJT e2 on e1.UniqEffect < e2.UniqEffect and e1.UniqIngredient = e2.UniqIngredient
       inner join IngredientEffectJT jt1 on jt1.UniqEffect = e1.UniqEffect and e1.UniqIngredient != jt1.UniqIngredient
   inner join IngredientEffectJT jt2 on jt2.UniqEffect = e2.UniqEffect and e1.UniqIngredient != jt2.UniqIngredient and jt1.UniqIngredient != jt2.UniqIngredient
       inner join Effect ee1 on e1.UniqEffect = ee1.ID
       inner join Effect ee2 on e2.UniqEffect = ee2.ID
   where ee1.Poison = ee2.Poison
;

编辑:忘记毒药检查。

编辑:try2 :(再次编辑以处理任何共享的成分,而不仅仅是最低ID)

select
  (select Name from Ingredient where ID = i1) as Ingredient1,
  (select Name from Ingredient where ID = i2) as Ingredient2,
  (select Name from Ingredient where ID = i3) as Ingredient3,
  min(Poison) as Poison
  -- , group_concat(Name) as Effects
  from
(
select
      a.*,
      min(e.Name) as Name,
      min(e.Poison) as Poison
   from
(
   select -- straight_join
          i1.ID as i1,
          i2.ID as i2,
          i3.ID as i3
   from IngredientEffectJT e1
       inner join IngredientEffectJT e2 on e1.UniqEffect < e2.UniqEffect and e1.UniqIngredient = e2.UniqIngredient
       inner join Effect ee1 on e1.UniqEffect = ee1.ID
       inner join Effect ee2 on e2.UniqEffect = ee2.ID and ee1.Poison = ee2.Poison
       inner join IngredientEffectJT jt1 on jt1.UniqEffect = e1.UniqEffect and e1.UniqIngredient != jt1.UniqIngredient
       inner join IngredientEffectJT jt2 on jt2.UniqEffect = e2.UniqEffect and jt1.UniqIngredient != jt2.UniqIngredient and e1.UniqIngredient != jt2.UniqIngredient
       inner join Ingredient i1
         on (i1.ID = e1.UniqIngredient  and e1.UniqIngredient < jt1.UniqIngredient and e1.UniqIngredient < jt2.UniqIngredient)
         or (i1.ID = jt1.UniqIngredient and jt1.UniqIngredient < e1.UniqIngredient and jt1.UniqIngredient < jt2.UniqIngredient)
         or (i1.ID = jt2.UniqIngredient and jt2.UniqIngredient < jt1.UniqIngredient and jt2.UniqIngredient < e1.UniqIngredient)
       inner join Ingredient i3
         on (i3.ID = e1.UniqIngredient  and e1.UniqIngredient > jt1.UniqIngredient and e1.UniqIngredient > jt2.UniqIngredient)
         or (i3.ID = jt1.UniqIngredient and jt1.UniqIngredient > e1.UniqIngredient and jt1.UniqIngredient > jt2.UniqIngredient)
         or (i3.ID = jt2.UniqIngredient and jt2.UniqIngredient > jt1.UniqIngredient and jt2.UniqIngredient > e1.UniqIngredient)
       inner join Ingredient i2 on i2.ID = e1.UniqIngredient + jt1.UniqIngredient + jt2.UniqIngredient - i1.ID - i3.ID
     group by i1.ID, i2.ID, i3.ID
) as a
inner join IngredientEffectJT as jt on a.i1 = jt.UniqIngredient or a.i2 = jt.UniqIngredient or a.i3 = jt.UniqIngredient
inner join Effect e on jt.UniqEffect = e.ID
group by i1, i2, i3, e.ID
having count(*) >= 2
) as b
group by b.i1, b.i2, b.i3
having sum(Poison) = count(*) or sum(Poison) = 0
-- order by count(distinct Name) desc
 order by i1, i2, i3
;

EDIT3:

对于SQL Server,将group_concat()行替换为:

  ,(
    (
    select min(e.Name) + ',' as [data()] from IngredientEffectJT jt
       inner join Effect e on jt.UniqEffect = e.ID
       where i1=jt.UniqIngredient or i2=jt.UniqIngredient or i3=jt.UniqIngredient
       group by jt.UniqEffect
       having COUNT(*) >= 2
       for xml path('')
    )
  ) as Effects

答案 2 :(得分:2)

这是一次性的。

;WITH IngredientCombinations AS
(
SELECT i1.UniqIngredient AS i1_UniqIngredient,
       i1.Name AS i1_Name,
       i2.UniqIngredient AS i2_UniqIngredient,
       i2.Name AS i2_Name,
       i3.UniqIngredient AS i3_UniqIngredient,
       i3.Name AS i3_Name,
       i1.UniqIngredient AS i1_UniqIngredientB,
       i2.UniqIngredient AS i2_UniqIngredientB,
       i3.UniqIngredient AS i3_UniqIngredientB       
FROM   Ingredient i1
       JOIN Ingredient i2
         ON i1.UniqIngredient < i2.UniqIngredient
       JOIN Ingredient i3
         ON i2.UniqIngredient < i3.UniqIngredient 
)
, UnpivotedIngredientCombinations AS
(
SELECT i1_UniqIngredient,
       i1_Name,
       i2_UniqIngredient,
       i2_Name,
       i3_UniqIngredient,
       i3_Name,
       UniqIngredient
FROM IngredientCombinations
UNPIVOT
   (UniqIngredient FOR idx IN 
      (i1_UniqIngredientB, i2_UniqIngredientB, i3_UniqIngredientB)
)AS unpvt),
Effects AS
(
SELECT uic.i1_Name,
       uic.i1_UniqIngredient,
       uic.i2_Name,
       uic.i2_UniqIngredient,
       uic.i3_Name,
       uic.i3_UniqIngredient,
       uic.UniqIngredient,
       e.Name,
       e.Poison,
       e.Potion,
       e.UniqEffect,
       COUNT(*) OVER (PARTITION BY i1_UniqIngredient, 
                                   i2_UniqIngredient,
                                   i3_UniqIngredient, 
                                   e.UniqEffect) AS Cnt
FROM   UnpivotedIngredientCombinations uic
       JOIN IngredientEffectJT iej
         ON iej.UniqIngredient = uic.UniqIngredient
       JOIN Effect e
         ON e.UniqEffect = iej.UniqEffect  
)
SELECT i1_Name,
       i2_Name,
       i3_Name
FROM   Effects
GROUP  BY i1_UniqIngredient,
          i2_UniqIngredient,
          i3_UniqIngredient,
          i1_Name,
          i2_Name,
          i3_Name
HAVING MAX(CASE
             WHEN Cnt = 2
                  AND Poison = 1 THEN 1
           END) IS NULL  

答案 3 :(得分:2)

好的,所以这是我拍摄的。

基于这些要求:

  • 只有药水,不允许有毒药
  • 两种或三种成分
  • 没有重复(1-2-3,3-2-1是相同的)
  • 所有成分必须有助于实现效果
  • 除非提供另一种效果,否则必须排除影响效果的成分

我希望表和字段名称都可以,我从我自己的表开始,但是使用你的数据。

select ing1.name, ing2.name, coalesce(ing3.name, ' ') from
(
-- Gives all unique combinations of two or three ingredients
    select ing1.UniqIngredient as id1, ing2.UniqIngredient as id2, 0 as id3
    from Ingredient as ing1
    inner join Ingredient as ing2 on ing1.UniqIngredient < ing2.UniqIngredient
    UNION
    select ing1.UniqIngredient as id1, ing2.UniqIngredient as id2, ing3.UniqIngredient as id3
    from Ingredient as ing1
    inner join Ingredient as ing2 on ing1.UniqIngredient < ing2.UniqIngredient
    inner join Ingredient as ing3 on ing2.UniqIngredient < ing3.UniqIngredient
) as MainRequest
join Ingredient as ing1 on ing1.UniqIngredient = id1
join Ingredient as ing2 on ing2.UniqIngredient = id2
left outer join Ingredient as ing3 on ing3.UniqIngredient = id3
where
(   -- Check if ingredients have common positive effects that are not covered by 3 ingredients (when a 3rd ingredient is present)
    exists(
    select eff.UniqEffect, count(*)
    from /Effect eff
    join IngredientEffectJT link on link.UniqEffect = eff.UniqEffect
    where eff.potion = 1 and link.UniqIngredient in (id1, id2, id3)
    group by eff.UniqEffect
    having count(*) = 2)
    AND
    not exists(
    select eff.UniqEffect, count(*)
    from Effect eff
    join IngredientEffectJT link on link.UniqEffect = eff.UniqEffect
    where eff.potion = 1 and link.UniqIngredient in (id1, id2, id3)
    group by eff.UniqEffect
    having count(*) > 2
    )
)
-- Check if ingredients have no common negative effects
AND not exists(
    select eff.UniqEffect, count(*)
    from Effect eff
    join IngredientEffectJT link on link.UniqEffect = eff.UniqEffect
    where eff.poison = 1 and link.UniqIngredient in (id1, id2, id3)
    group by eff.UniqEffect
    having count(*) >= 2)
-- Check if every ingredient is participating (No alchemist likes a freerider)
AND exists(select link1.UniqIngredient
    from IngredientEffectJT link1
    inner join IngredientEffectJT link2 on link1.UniqEffect = link2.UniqEffect
    where link1.UniqIngredient = id1 and link2.UniqIngredient in (id2, id3))
AND exists(select link1.UniqIngredient
    from IngredientEffectJT link1
    inner join IngredientEffectJT link2 on link1.UniqEffect = link2.UniqEffect
    where link1.UniqIngredient = id2 and link2.UniqIngredient in (id1, id3))
AND (id3 = 0 or
    exists(select link1.UniqIngredient
    from IngredientEffectJT link1
    inner join IngredientEffectJT link2 on link1.UniqEffect = link2.UniqEffect
    where link1.UniqIngredient = id3 and link2.UniqIngredient in (id1, id2)))

答案 4 :(得分:0)

虽然马丁史密斯的解决方案并没有完全解决这个问题,但它确实激励我考虑使用CTE,我想我已经得到了它。

一旦我意识到每3种成分组合实际上是2种不同的2种成分组合,它们共有1种常见成分,我决定找到所有2种成分组合,然后找到至少有1种成分的两种成分组合,并且都有效果另一个没有。

然后检查以确保每3种成分组合没有毒害效果(我已经知道每个人2种成分组合没有毒害作用,但仅仅因为A + B没有毒药而且B + C没有毒药并不意味着A + B + C不会有毒药。将A与C结合会产生毒害效果。)

然后我将所有3种成分连接回效果表,以显示每种组合产生的效果。

此查询在我的系统上有3分50秒的执行时间。这不酷。但至少我现在得到了我想要的结果。

WITH Combination AS
(
    --Finds all 2 ingredient combinations that have shared effects that are not poisons
    select ROW_NUMBER() OVER (ORDER BY i1.Name, i2.Name) UniqCombination, i1.UniqIngredient UniqIngredient1, i2.UniqIngredient UniqIngredient2, COUNT(1) NumberOfEffects
    from Ingredient i1
    cross join Ingredient i2
    INNER JOIN IngredientEffectJT jt1 ON i1.UniqIngredient = jt1.UniqIngredient
    INNER JOIN IngredientEffectJT jt2 ON i2.UniqIngredient = jt2.UniqIngredient
    INNER JOIN Effect e ON jt1.UniqEffect = e.UniqEffect AND jt2.UniqEffect = e.UniqEffect
    WHERE i1.UniqIngredient < i2.UniqIngredient
    GROUP BY i1.UniqIngredient, i1.name, i2.UniqIngredient, i2.Name
    HAVING SUM(e.poison) = 0
),
Potion AS
(
    --Matches up all 2 ingredient combinations in the Combination CTE with the effects for that combination
    SELECT DISTINCT c.UniqCombination, c.UniqIngredient1, i1.Name Ingredient1, c.UniqIngredient2, i2.Name Ingredient2, e.UniqEffect, e.Name Effect
    FROM Combination c
    INNER JOIN Ingredient i1 ON c.UniqIngredient1 = i1.UniqIngredient
    INNER JOIN Ingredient i2 ON c.UniqIngredient2 = i2.UniqIngredient
    INNER JOIN IngredientEffectJT jt1 ON c.UniqIngredient1 = jt1.UniqIngredient
    INNER JOIN IngredientEffectJT jt2 ON c.UniqIngredient2 = jt2.UniqIngredient
    INNER JOIN Effect e ON jt1.UniqEffect = e.UniqEffect AND jt2.UniqEffect = e.UniqEffect

),
BigCombination AS
(
    --Matches 2 combinations together where 1 ingredient is the same in both combinations.
    SELECT c1.UniqIngredient1, CASE WHEN c1.UniqIngredient1 = c2.UniqIngredient1 THEN c1.UniqIngredient2 ELSE c2.UniqIngredient1 END UniqIngredient2, c2.UniqIngredient2 UniqIngredient3
    FROM Combination c1
    INNER JOIN Combination c2 ON (c1.UniqIngredient1 = c2.UniqIngredient1 OR c1.UniqIngredient2 = c2.UniqIngredient1 OR c1.UniqIngredient2 = c2.UniqIngredient2) AND c1.UniqCombination < c2.UniqCombination
    --This WHERE clause sucks because there are 2 different select queries that must run twice each.
    --They have to run twice because I have to EXCEPT 1 from 2 and 2 from 1 to make sure both combinations are contributing something new.
    WHERE EXISTS( SELECT p1.UniqEffect
                  FROM Potion p1
                  WHERE p1.UniqCombination = c1.UniqCombination
                  EXCEPT
                  SELECT p2.UniqEffect
                  FROM Potion p2
                  WHERE p2.UniqCombination = c2.UniqCombination)
    AND EXISTS( SELECT p2.UniqEffect
                FROM Potion p2
                WHERE p2.UniqCombination = c2.UniqCombination
                EXCEPT
                SELECT p1.UniqEffect
                FROM Potion p1
                WHERE p1.UniqCombination = c1.UniqCombination)
),
BigPotionCombination AS
(
    --Combinations were made only from other combinations that made potions, but it's possible the new
    --ingredients mixing together could create a new poison effect. This will remove combinations that create new poison effects
    SELECT DISTINCT c.*
    FROM BigCombination c
    INNER JOIN IngredientEffectJT jt1 ON c.UniqIngredient1 = jt1.UniqIngredient
    INNER JOIN IngredientEffectJT jt2 ON c.UniqIngredient2 = jt2.UniqIngredient
    INNER JOIN IngredientEffectJT jt3 ON c.UniqIngredient3 = jt3.UniqIngredient
    INNER JOIN Effect e ON (jt1.UniqEffect = e.UniqEffect AND (jt2.UniqEffect = e.UniqEffect OR jt3.UniqEffect = e.UniqEffect)) OR (jt2.UniqEffect = e.UniqEffect AND jt3.UniqEffect = e.UniqEffect)
    GROUP BY c.UniqIngredient1, c.UniqIngredient2, c.UniqIngredient3
    HAVING SUM(e.Poison) = 0
)

--Combinations have to be joined back to Effect again to display the effects that the potions have.
SELECT DISTINCT i1.Name Ingredient1, i2.Name Ingredient2, i3.Name Ingredient3, e.Name Effect
FROM BigPotionCombination c
INNER JOIN Ingredient i1 ON c.UniqIngredient1 = i1.UniqIngredient
INNER JOIN Ingredient i2 ON c.UniqIngredient2 = i2.UniqIngredient
INNER JOIN Ingredient i3 ON c.UniqIngredient3 = i3.UniqIngredient
INNER JOIN IngredientEffectJT jt1 ON c.UniqIngredient1 = jt1.UniqIngredient
INNER JOIN IngredientEffectJT jt2 ON c.UniqIngredient2 = jt2.UniqIngredient
INNER JOIN IngredientEffectJT jt3 ON c.UniqIngredient3 = jt3.UniqIngredient
INNER JOIN Effect e ON (jt1.UniqEffect = e.UniqEffect AND (jt2.UniqEffect = e.UniqEffect OR jt3.UniqEffect = e.UniqEffect)) OR (jt2.UniqEffect = e.UniqEffect AND jt3.UniqEffect = e.UniqEffect)
ORDER BY Ingredient1, Ingredient2, Ingredient3, Effect

答案 5 :(得分:-1)