Как расширить этот запрос, чтобы найти допустимые комбинации из трех элементов?
Я полностью не ожидаю получить ответы здесь, но я все равно попробую.
Так получилось, что он играл в Скайрима. Я хотел найти простой способ найти, какие ингредиенты могут быть объединены, чтобы сделать разные зелья/яды, поэтому я сделал таблицу ингредиентов с идентификатором и именем; таблица эффектов, в которой есть идентификатор, имя, флаг отравления и флаг зелья (зелье и яд являются взаимоисключающими); и таблицу соединений, у которой есть идентификатор для ингредиента и идентификатора для эффекта.
Таким образом, как это работает, каждый ингредиент имеет 4 разных эффекта, эффекты повторяются на многообразных ингредиентах. В игре вы можете комбинировать 2 или 3 ингредиента, и результат - зелье или яд со всеми эффектами, которые соответствуют по меньшей мере двум ингредиентам. Поэтому, если вы используете 3 ингредиента и эффект1 находится на обоих ингредиентах1 и ингредиент2, а эффект2 находится на обоих ингредиентах1 и ингредиенте3, ваш результат будет зельем/ядом, который имеет эффект effect1 и effect2.
Я смог придумать свой запрос, который покажет все возможные комбинации ингредиентов, которые создают зелье без ядовитых эффектов. Сначала мне нужно найти все возможное сочетание двух ингредиентов, которое имеет только соответствующие эффекты, которые не являются "ядом":
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 < i2.UniqIngredient. Я буду когда-либо видеть каждую комбинацию один раз, а нижний идентификатор из 2 ингредиентов всегда будет в 1-й колонке.
Я соединяю оба ингредиента с тем же эффектом, потому что мне только заботятся о комбинациях, которые дают результат.
Затем я группирую их по 2 ингредиентам и подсчитываю, сколько ядовитых эффектов они разделяют, потому что мне нужны только комбинации, которые имеют 0 ядовитых эффектов.
Затем я использую этот результат как таблицу, к которой я присоединяюсь к таблицам Ингредиент и Эффект, чтобы получить список всех возможных комбинаций ингредиентов, которые производят зелья, и о том, что влияет на каждую комбинацию:
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.
Это все хорошо и хорошо, но когда я хочу представить третий ингредиент, где это становится сложно. Я в тупике. Я могу изменить этот запрос, чтобы проверить наличие 3 ингредиентов, которые имеют одинаковый эффект, но это не то, что я хочу. Я хочу найти третий ингредиент, который имеет общий эффект с одним из ингредиентов.
Любая помощь?
ИЗМЕНИТЬ
Обновление: поэтому, после долгих часов работы с этим, я придумал большой, уродливый, медленный, труднопроданный запрос (на самом деле я даже не помню, почему мне пришлось делать это безумное условие соединения в таблице Effect. Но когда я меняю его, весь запрос на 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... На самом деле я не помню, к чему сумасшедшее соединение для Effect. Глядя на это, я думал, что это должно обеспечить эффект, по крайней мере, на 2 ингредиента, но то, что делает предложение WHERE. И упрощение этого соединения эффектов приводит к тому, что он работает значительно медленнее, поэтому... что угодно.
Тогда GROUP BY существует, поэтому я могу подсчитать количество соответствующих ядовитых эффектов. Поскольку мне приходилось группировать по 3 ингредиентам, я теряю индивидуальные эффекты, поэтому мне нужно снова присоединить все эти ингредиенты к их эффектам и найти эффекты, которые соответствуют.
Проблема с этим запросом заключается в том, что он отобразит комбинации, в которых все 3 ингредиента имеют один и тот же эффект. Эти комбинации бессмысленны, потому что вы можете сделать одно и то же, используя только 2 из этих 3, поэтому это расточительно.
Итак, это лучшее, что я мог придумать. Это очень медленно, поэтому, возможно, я просто сохраню его в новой таблице, чтобы упростить и ускорить запрос в будущем.
Ответы
Ответ 1
В то время как решение Martin Smith не полностью решает эту проблему, оно вдохновило меня на изучение использования CTE, и я думаю, что получил его.
Как только я понял, что каждая комбинация из 3 ингредиентов - это действительно 2 разных комбинаций ингредиентов, которые разделяют 1 общий ингредиент, я решил найти все 2 комбинации ингредиентов, а затем найти любую комбинацию из тех, у которых есть по крайней мере один ингредиент, и оба эффекта что другой не имеет.
Затем убедитесь, что каждая комбинация из 3 ингредиентов не имеет ядовитых эффектов (я уже знаю, что каждая индивидуальная комбинация ингредиентов не имеет ядовитых эффектов, а только потому, что у A + B нет яда, а у B + C нет яда, это не значит A + B + C не будет иметь яда. Возможно, что расческа A с C вызовет ядовитый эффект).
Затем я присоединяю все 3 ингредиента к таблице Effect, чтобы отобразить, какие эффекты производятся с каждой комбинацией.
У этого запроса есть 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 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
Ответ 2
Попробуйте это
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
Ответ 3
Не уверен, как это будет выполняться, но это намного проще, я думаю:
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
;
РЕДАКТИРОВАТЬ: Забыть проверку яда.
EDIT: 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
Ответ 4
Здесь один идет на него.
;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
Ответ 5
Хорошо, так вот мой снимок.
Он основан на следующих требованиях:
- Только зелья, не допускается ядовитый эффект.
- Два или три ингредиента
- Нет дубликатов (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)))
Ответ 6
Это работает очень хорошо. http://rp.eliteskills.com/skyrim.html