2011-12-14 27 views
11

Tôi hoàn toàn không mong đợi để có được bất kỳ câu trả lời ở đây, nhưng tôi sẽ thử anyway.Làm cách nào để mở rộng truy vấn này để tìm các kết hợp hợp lệ của ba mục?

Vì vậy, điều này xuất phát từ Skyrim. Tôi muốn một cách dễ dàng để tìm kiếm những thành phần có thể được kết hợp để làm cho potions/chất độc khác nhau vì vậy tôi đã thực hiện một bảng thành phần có một ID và một tên; một bảng hiệu ứng có một ID, tên, cờ Poison và cờ Potion (thuốc và chất độc là loại trừ lẫn nhau); và một bảng tham gia có ID cho thành phần và ID có hiệu lực.

Cách hoạt động là mọi thành phần có 4 hiệu ứng khác nhau, hiệu ứng được lặp lại trên các thành phần mulitple. Trong trò chơi, bạn có thể kết hợp 2 hoặc 3 thành phần và kết quả là một loại thuốc hoặc chất độc với tất cả các hiệu ứng phù hợp với ít nhất 2 thành phần được sử dụng. Vì vậy, nếu bạn sử dụng 3 thành phần và effect1 là trên cả hai thành phần1 và ingredients2 và effect2 là trên cả hai thành phần1 và ingredients3 kết quả của bạn sẽ là một potion/chất độc có cả effect1 và effect2.

Tôi có thể tự mình tìm ra một câu hỏi sẽ hiển thị mọi kết hợp 2 thành phần có thể tạo ra một loại thuốc không có tác dụng độc. Đầu tiên tôi cần phải tìm mọi kết hợp 2 thành phần có thể là chỉ có tác dụng mà không phải là "thuốc độc" phù hợp với:

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 

Ingredient là cross tham gia với thành phần để có được tất cả các kết hợp nhưng vì thứ tự của các thành phần không quan trọng , Tôi sẽ kết thúc với gấp đôi kết quả. Đó là lý do tại sao WHERE kiểm tra i1.UniqIngredient < i2.UniqIngredient. Tôi sẽ chỉ thấy mỗi kết hợp một lần và ID thấp hơn của 2 thành phần sẽ luôn ở trong cột thứ nhất. Tôi tham gia cả hai thành phần với cùng một hiệu ứng, bởi vì tôi chỉ quan tâm đến các kết hợp tạo ra kết quả. Sau đó, tôi nhóm chúng theo 2 thành phần và đếm số lượng hiệu ứng độc mà chúng chia sẻ vì tôi chỉ muốn kết hợp có 0 hiệu ứng độc.

Sau đó, tôi sử dụng kết quả này như một bảng mà tôi tham gia trở lại các bảng thành phần và có hiệu lực để có được một danh sách của tất cả các kết hợp 2 thành phần có thể là sản xuất potions, và những gì tác động từng tổ hợp có:

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 

Sử dụng cùng một truy vấn tôi có thể tìm thấy 2 kết hợp chất độc thành phần không có tác dụng thuốc chỉ bằng cách thay đổi đường HAVING để kiểm tra e.Potion thay vì e.Poison.

Điều này là tốt và tốt, nhưng khi tôi muốn giới thiệu thành phần thứ 3 là nơi nó trở nên phức tạp. Tôi bối rối. Tôi có thể sửa đổi truy vấn này để kiểm tra 3 thành phần mà tất cả đều có tác dụng tương tự, nhưng đó không phải là những gì tôi muốn. Tôi muốn tìm một thành phần thứ 3 có tác dụng khác với 1 trong số các thành phần.

Bất kỳ trợ giúp nào?


EDIT


Cập nhật: Vì vậy, sau khi vật lộn với điều này trong nhiều giờ tôi đã đưa ra một lớn, xấu xí, chậm, khó có thể làm theo truy vấn (Tôi thực sự thậm chí không nhớ tại sao tôi phải làm điều đó điên cuồng tham gia điều kiện trên bảng Effect. Nhưng khi tôi thay đổi nó toàn bộ truy vấn là 2x chậm hơn vì vậy nó thực sự nhanh hơn cách tôi có nó, mặc dù tôi không biết tại sao ...), rằng gần như thực hiện những gì tôi muốn. Điều này có thể gần như tôi có thể nhận được, trừ khi ai đó có bất kỳ ý tưởng nào khác hoặc nhìn thấy một cách để cải thiện truy vấn mới của tôi.

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 

Trong truy vấn bên trong:

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

Điều này tạo ra mọi sự kết hợp có thể có của 3 thành phần mà tự không quan trọng và không có gì được lặp lại. Sau đó, các Joins để IngredientEffectJT và Effect ... Tôi thực sự không nhớ những gì tham gia điên trên Effect là cho. Nhìn vào nó, tôi nghĩ rằng đó là để đảm bảo một hiệu ứng tồn tại trên ít nhất 2 thành phần, nhưng đó là những gì mệnh đề WHERE đang làm. Và đơn giản hóa việc kết hợp hiệu ứng đó làm cho nó chạy chậm hơn đáng kể nên ... bất cứ điều gì.

Sau đó, GROUP BY có ở đó để tôi có thể đếm số hiệu ứng độc phù hợp. Vì tôi phải nhóm theo 3 thành phần, tôi mất các hiệu ứng kết hợp cá nhân nên tôi cần phải tham gia lại tất cả các thành phần đó trở lại hiệu ứng của chúng và tìm ra các hiệu ứng phù hợp.

Vấn đề với truy vấn này là nó sẽ hiển thị kết hợp trong đó tất cả 3 thành phần có cùng 1 hiệu ứng. Những kết hợp này là vô nghĩa bởi vì bạn có thể làm điều tương tự bằng cách chỉ sử dụng 2 trong số 3 cái đó để nó lãng phí.

Vì vậy, đây là điều tốt nhất tôi có thể nghĩ ra. Nó thực sự chậm vì vậy có lẽ tôi sẽ chỉ lưu nó vào một bảng mới để làm cho nó dễ dàng hơn và nhanh hơn để truy vấn lại trong tương lai.

+0

Bạn có thể cung cấp bất kỳ dữ liệu mẫu nào không? – Aaron

+0

Thử thách thú vị, tôi sẽ thử và quay lại với bạn. –

+0

Upvote cho Skyrim tham khảo – JackAce

Trả lời

0

Trong khi giải pháp Martin Smith không hoàn toàn giải quyết vấn đề này, nó đã truyền cảm hứng cho tôi để nhìn vào sử dụng CTEs và tôi nghĩ rằng tôi đã nhận nó. Một khi tôi nhận ra mỗi sự kết hợp 3 thành phần thực sự là 2 kết hợp thành phần khác nhau chia sẻ 1 thành phần phổ biến, tôi quyết định tìm tất cả 2 thành phần kết hợp và sau đó tìm thấy sự kết hợp của những người có ít nhất 1 thành phần chung và cả hai đều có hiệu ứng mà người kia không có. Sau đó kiểm tra để đảm bảo rằng mỗi hỗn hợp 3 thành phần không có tác dụng độc (tôi đã biết từng kết hợp 2 thành phần không có tác dụng độc, nhưng chỉ vì A + B không có độc và B + C không có chất độc có nghĩa là A + B + C sẽ không có chất độc. Có thể việc chải A với C sẽ tạo ra hiệu ứng độc).

Sau đó, tôi kết hợp tất cả 3 thành phần trở lại bảng Hiệu ứng để hiển thị hiệu ứng nào được tạo ra với mỗi kết hợp.

Truy vấn này có thời gian thực hiện 3 phút 50 giây trên hệ thống của tôi. Đó không phải là mát mẻ. Nhưng ít nhất tôi đang nhận được kết quả tôi muốn bây giờ.

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

Hãy thử điều này

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 
+0

Vấn đề với giải pháp của bạn là nó cho thấy tất cả các kết hợp tạo ra một hiệu ứng ngay cả khi một trong các thành phần trong sự kết hợp đó là không ' t cần thiết. Ví dụ khi tôi chạy chạy mà combo đầu tiên nó tìm thấy có 3 thành phần, các thành phần 1 không có bất cứ điều gì chung với thành phần thứ 2 hoặc thứ 3. nó hiển thị như một kết hợp vì # 2 và 3 có điểm chung. Tôi không muốn các kết hợp như thế này xuất hiện. – Nick

+0

Ahh, OK. Bạn chỉ muốn kết hợp mà tất cả các thành phần đóng góp vào một hiệu ứng. Tôi có thể chỉnh sửa để xóa các kết hợp đó. Điều gì về sự kết hợp có chứa một thành phần đóng góp cho cùng, và chỉ, có hiệu lực như hai thành phần đầu tiên? – jmacinnes

+0

Vâng, tôi chỉ muốn kết hợp mà mọi thành phần đều đóng góp một hiệu ứng. Trong trường hợp cả 3 thành phần cung cấp hiệu ứng tương tự, tôi không muốn những thành phần đó. Trừ khi họ cũng cung cấp một hiệu ứng mới. – Nick

2

Không chắc chắn cách này sẽ thực hiện, nhưng nó đơn giản hơn rất nhiều Tôi nghĩ:

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: Quên kiểm tra Poison.

EDIT: try2: (thay đổi nội dung một lần nữa để xử lý bất kỳ thành phần như chia sẻ, không chỉ ID thấp nhất)

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:

Đối với SQL Server thay thế group_concat() phù hợp với:

,(
    (
    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 
+0

Bạn hiển thị các cột cho Effect1 và Effect2, nhưng kết hợp 3 thành phần có thể có tới 6 hiệu ứng. Thành phần1 có thể có các hiệu ứng A, B, C và D; Thành phần 2 có thể có các hiệu ứng A, B, E, F; Thành phần3 có thể có hiệu ứng C, D, E, F. Kết quả sẽ có hiệu ứng A, B, C, D, E và F. – Nick

+0

@ user862495: Ah, tôi nghĩ rằng tôi đã hiểu sai câu lệnh ... –

+0

@ user862495 Đã sửa đổi để hiển thị tất cả các hiệu ứng và loại bỏ các bộ thành phần trùng lặp. (chạy trong khoảng 1 giây trên hệ thống của tôi). p.s. - Các hiệu ứng tôi thấy trong một lần truyền là 4. (Tôi đã thử nghiệm với 6 nhưng phải thay đổi dữ liệu) –

2

Đây là một trong số đó.

;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 
+0

Điều này mang lại sự kết hợp mà không phải tất cả 3 thành phần đều có tác dụng góp phần.Tôi không biết nếu bạn chạy kịch bản tôi tải lên nhưng nếu bạn đã làm và có các bảng dân cư bạn có thể thấy truy vấn của bạn trả về kết hợp của Abecean Longfin + Bear Claws + Bee mặc dù Abecean Longfin không có điểm chung với Bear Claws hoặc Bee . nó chỉ hiển thị như một sự kết hợp cung cấp một kết quả bởi vì Bear Claws và Bee có điểm chung. – Nick

2

Ok, vậy đây là ảnh của tôi.

Nó được dựa trên các yêu cầu:

  • Potions duy nhất, không có tác dụng độc cho phép
  • Hai hoặc ba thành phần
  • Không lặp (1-2-3, 3-2-1 là cùng)
  • Tất cả các thành phần phải được góp phần ảnh hưởng
  • Thành phần được trippling ảnh hưởng phải được loại trừ trừ trường hợp cung cấp hiệu ứng khác

Tôi hy vọng các tên bảng và trường là ok, tôi bắt đầu với các bảng của riêng tôi nhưng với dữ liệu của bạn.

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))) 
+0

Tôi đang thấy Abecean Longfin + Beehive Husk + Blisterwort trong kết quả sử dụng truy vấn của bạn, nhưng Blisterwort không có tác dụng chung với một trong hai loại khác 2. Ngoài ra, Briar Heart + Red Mountain Flower + Tundra Cotton không xuất hiện trong kết quả của bạn, tôi nghĩ rằng nó đang được lọc ra bởi vì tất cả 3 có Fortify Magicka, nhưng nó không nên được lọc ra vì 'Briar Heart' + 'Red Mountain Flower' thêm 'Restore Magicka' và 'Briar Heart' + 'Tundra Cotton 'thêm' Fortify Block ' Tôi sẽ đăng truy vấn mới tôi đã đưa ra ở đây, có vẻ như nó hoạt động chính xác như tôi hy vọng, nhưng nó vẫn còn khá chậm. – Nick

+0

Hmmm bạn nói đúng. Tôi sẽ cố gắng tìm một số thời gian để cập nhật truy vấn của mình để đề cập đến điều này. Điều này sẽ tối ưu hóa việc sản xuất thuốc/chất độc của tôi trong Skyrim quá :) –

-1

Cái này hoạt động khá tốt. http://rp.eliteskills.com/skyrim.html

+0

Đó không phải là điều tôi muốn. Tôi không muốn chỉ định một thành phần và xem những gì nó có thể được sử dụng với. Tôi muốn xem tất cả các kết hợp khác nhau. làm nó trong DB của riêng tôi, tôi thậm chí có thể nhập số lượng của mỗi thành phần tôi có và lọc kết quả của truy vấn để hiển thị mọi kết hợp có thể có của các thành phần tôi có. – Nick

+0

Nó tạo ra tất cả các hoán vị. Nhấp vào "Thêm tất cả" và đặt giới hạn thành 16000. Nó sẽ hiển thị cho bạn tất cả hoán vị có thể không lặp lại. Điều này cho một giá trị như vậy cho thấy đắt nhất đầu tiên. Đó là kinda tẻ nhạt để nhập vào tất cả các thành phần số tiền và làm cho brute forcer. Nói chung bạn có thể dễ dàng làm cho vô số tiền nghiền các công thức nấu ăn hàng đầu. Điều này là tốt cho lọc ra potions với một tập hợp cụ thể của hiệu ứng mong muốn. –

+0

Đó vẫn không phải là điều tôi muốn. Tôi chỉ muốn thấy những thứ tôi có thể làm với những nguyên liệu tôi có. Cơ sở dữ liệu của tôi biết các thành phần của tôi. – Nick

Các vấn đề liên quan