2013-05-10 176 views
2

我正在使用PHP和MySQL。 任何人都可以告诉我一个有效的方法来筛选出基于优先级的重复结果吗?基于列优先级的SQL筛选器重复项

实施例:

我有一个表:

ID | Priority 1 | Priority 2 | Priority 3 | E-Mail 
-------------------------------------------------------------- 
1 | Apple  | One   | Low   | [email protected] 
2 | Banana  | Two   | Medium  | [email protected] 
3 | Banana  | Two   | High  | [email protected] 
4 | Banana  | Two   | High  | [email protected] 
5 | Peach  | Three  | Low   | [email protected] 
6 | Peach  | Four  | High  | [email protected] 

在上述例子中,我在寻找一种方法来只获得行1,3(或4)和6
即就像第2,3,4行的电子邮件和5,6是相同的,它们是重复的记录。我想根据优先级选择记录。
如果重复记录的优先级1是相同的,我将转到优先级2.如果这也是相同的,那么我将转到优先级3.如果相同,那么选择哪个并不重要。
但是,如果有差异,我选择较高优先级的记录。 在上面的例子中,优先级是

Peach -> Banana -> Apple 
Four -> Three -> Two -> One 
High -> Medium -> Low 

然后我将插入结果到不同的数据库中。

到目前为止,我有一个查询来获取非重复。我正在考虑处理重复的第二个查询。
第一个查询处理约20,000条记录。第二个查询将处理大约5,000条记录。

但是,我不确定完成该操作的有效方法。

我非常感谢任何帮助。

谢谢。

编辑:错字:希望行1,3/4和6(没有1,2和6)

+0

为什么记录2,具有中等优先级,而不是3或4? – fthiella 2013-05-10 19:23:34

+0

正常化任何人? – Strawberry 2013-05-13 22:49:08

回答

0

该查询应该给你,你需要的结果:

SELECT 
    MIN(ID), 
    EMail, 
    MIN(Priority1), 
    MIN(Priority2), 
    MIN(Priority3) 
FROM 
    yourtable 
WHERE 
    (EMail, Priority1, Priority2, FIELD(Priority3, 'High', 'Medium', 'Low')) IN (
    SELECT 
     EMail, 
     MIN(Priority1), 
     MIN(Priority2), 
     MIN(FIELD(Priority3, 'High', 'Medium', 'Low')) MinP3 
    FROM 
     yourtable 
    WHERE 
     (EMail, Priority1, FIELD(Priority2, 'Four', 'Three', 'Two', 'One')) IN (
     SELECT 
      EMail, 
      MIN(Priority1), 
      MIN(FIELD(Priority2, 'Four', 'Three', 'Two', 'One')) MinP2 
     FROM 
      yourtable 
     WHERE 
      (EMail, FIELD(Priority1, 'Peach', 'Banana', 'Apple')) IN 
      (SELECT 
      EMail, MIN(FIELD(Priority1, 'Peach', 'Banana', 'Apple')) MinP1 
      FROM 
      yourtable 
      GROUP BY 
      EMail) 
     GROUP BY 
      EMail) 
    GROUP BY 
     EMail) 
GROUP BY 
    EMail 

(我返回第3行而不是2,但如果我正确理解你的问题,它应该是正确的)。请参阅小提琴here。我怀疑它不会很快。我仍然想知道是否有办法让它更快。

编辑

您可以尝试以下查询。它使用了一种不同的逻辑,但它也使用带有某些列的Priorities表,它们应该比FIELD函数快得多,但是有很多连接可能会减慢查询的速度。

CREATE TABLE Priorities (
    Num INT, 
    Des VARCHAR(10), 
    Priority INT, 
    PRIMARY KEY (Num, Des) 
); 

INSERT INTO Priorities VALUES 
(1, 'Peach', 1), 
(1, 'Banana', 2), 
(1, 'Apple', 3), 
(2, 'Four', 1), 
(2, 'Three', 2), 
(2, 'Two', 3), 
(2, 'One', 4), 
(3, 'High', 1), 
(3, 'Medium', 2), 
(3, 'Low', 3); 

SELECT MIN(ID), yourtable.Email, MIN(Priority1) Priority1, MIN(Priority2) Priority2, MIN(Priority3) Priority3 
FROM 
    yourtable 
    INNER JOIN Priorities p1 ON yourtable.Priority1=p1.Des AND p1.Num=1 
    INNER JOIN Priorities p2 ON yourtable.Priority2=p2.Des AND p2.Num=2 
    INNER JOIN Priorities p3 ON yourtable.Priority3=p3.Des AND p3.Num=3 
    INNER JOIN (
    SELECT s1.EMail, MIN(MinP1) M1, MIN(MinP2) M2, MIN(MinP3) M3 
    FROM (
     SELECT EMail, MIN(p1.Priority) MinP1 
     FROM  yourtable INNER JOIN Priorities p1 
       ON yourtable.Priority1 = p1.Des AND p1.Num = 1 
     GROUP BY EMail) s1 
    INNER JOIN (
     SELECT EMail, p1.Priority Pr1, MIN(p2.Priority) MinP2 
     FROM  yourtable INNER JOIN Priorities p1 
       ON yourtable.Priority1 = p1.Des AND p1.Num = 1 
       INNER JOIN Priorities p2 
       ON yourtable.Priority2 = p2.Des AND p2.Num = 2 
     GROUP BY EMail, p1.Priority) s2 
    ON s1.EMail=s2.EMail AND s1.MinP1=s2.Pr1 
    INNER JOIN (
     SELECT EMail, p1.Priority Pr1, p2.Priority Pr2, MIN(p3.Priority) MinP3 
     FROM  yourtable INNER JOIN Priorities p1 
       ON yourtable.Priority1 = p1.Des AND p1.Num = 1 
       INNER JOIN Priorities p2 
       ON yourtable.Priority2 = p2.Des AND p2.Num = 2 
       INNER JOIN Priorities p3 
       ON yourtable.Priority3 = p3.Des AND p3.Num = 3 
     GROUP BY EMail, p1.Priority, p2.Priority) s3 
    ON s1.Email=s3.Email AND s1.MinP1=s3.Pr1 AND s2.MinP2=s3.Pr2 
    GROUP BY 
    s1.EMail) s 
    ON yourtable.EMail=s.Email 
    AND p1.Priority=s.M1 
    AND p2.Priority=s.M2 
    AND p3.Priority=s.M3 
GROUP BY 
    yourtable.EMail 

请参阅小提琴here。如果它仍然太慢,我们可以尝试使用我的第一个查询与第二个支持表一样。或者我们应该将查询分为两部分。

+0

嗨,非常感谢你如此快速的回应和你的时间。对此,我真的非常感激。是的,我想要第3行(不是2) - 感谢您的支持!这确实解决了这个问题,并且这比我现在的解决方案还要快(把结果放入一个数组然后过滤它)。但是,如果您能找到更快的解决方案,我将非常感激。再次谢谢你! – 2013-05-10 20:15:06

+0

嗨,我试着在超过20,000条记录的实际数据库上运行这个查询,并且超时。约100条记录需要5秒以上。虽然,我感谢您的帮助,但此解决方案无法在数据库上运行。你还有其他建议吗?也许我可以分开查询 - 首先我得到非重复的,然后我得到重复的记录,并过滤只是基于优先事项?谢谢! – 2013-05-13 13:59:16

+0

@CheekuJee查询很好,我认为,还有其他解决方案,但它们非常相似。我认为问题在于FIELD()函数缓慢。你应该使用索引的一些额外的表,只是给我一些时间,我会更新我的答案 – fthiella 2013-05-13 21:20:16