Я полностью не ожидаю получить ответы здесь, но я все равно попробую.
Так получилось, что он играл в Скайрима. Я хотел найти простой способ найти, какие ингредиенты могут быть объединены, чтобы сделать разные зелья/яды, поэтому я сделал таблицу ингредиентов с идентификатором и именем; таблица эффектов, в которой есть идентификатор, имя, флаг отравления и флаг зелья (зелье и яд являются взаимоисключающими); и таблицу соединений, у которой есть идентификатор для ингредиента и идентификатора для эффекта.
Таким образом, как это работает, каждый ингредиент имеет 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, поэтому это расточительно.
Итак, это лучшее, что я мог придумать. Это очень медленно, поэтому, возможно, я просто сохраню его в новой таблице, чтобы упростить и ускорить запрос в будущем.