2013-05-29 129 views
5

我的数据库中包含的行通常是这样的:MySQL查询查找具有相同的值作为另一行的所有行

PersonItem 
__________ 
id 
personId 
itemId 

╔════╦══════════╦════════╗ 
║ ID ║ PERSONID ║ ITEMID ║ 
╠════╬══════════╬════════╣ 
║ 1 ║  123 ║ 456 ║ 
║ 2 ║  123 ║ 456 ║ 
║ 3 ║  123 ║ 555 ║ 
║ 4 ║  444 ║ 456 ║ 
║ 5 ║  123 ║ 456 ║ 
║ 6 ║  333 ║ 555 ║ 
║ 7 ║  444 ║ 456 ║ 
╚════╩══════════╩════════╝ 

我需要找到所有的实际记录中,其中PERSONID和ITEMID列匹配一些在这两列的数据库中的其他记录....

| 1 | 123 | 456 
| 2 | 123 | 456 
| 5 | 123 | 456 

| 4 | 444 | 456 
| 7 | 444 | 456 

我该如何去获得这些结果?

+0

你的意思是两个匹配,或至少一个匹配? –

+0

哪里都匹配 – kasdega

回答

7

您可以通过连接来解决重复记录。

SELECT a.* 
FROM TableName a 
     INNER JOIN 
     (
      SELECT PersonID, ItemID, COUNT(*) totalCount 
      FROM TableName 
      GROUP BY PersonID, ItemID 
      HAVING COUNT(*) > 1 
     ) b ON a.PersonID = b.PersonID AND 
       a.ItemID = b.ItemID 

输出

╔════╦══════════╦════════╗ 
║ ID ║ PERSONID ║ ITEMID ║ 
╠════╬══════════╬════════╣ 
║ 1 ║  123 ║ 456 ║ 
║ 2 ║  123 ║ 456 ║ 
║ 5 ║  123 ║ 456 ║ 
║ 4 ║  444 ║ 456 ║ 
║ 7 ║  444 ║ 456 ║ 
╚════╩══════════╩════════╝ 
+0

这正是我想要的,并且花费最少的时间来完成它。谢谢。 – kasdega

+0

你有两列的索引? 'INDEX(PersonID,ItemID)'?它会变得更快。 –

+0

我在两列上都有索引,并且查询运行得很好。约50万条记录上有50ms。 – kasdega

3

您需要查找其中personid/itemid对多次出现的示例。在MySQL中,你可以用where子句和子查询做到这一点:

select t.* 
from t 
where exists (select 1 
       from t t2 
       group by personid, itemid 
       having count(*) > 1 and 
        t2.personid = t.personid and t2.itemid = t.itemid 
      ) 

以上是标准的SQL。 MySQL还支持多列in声明。因此,这可以写成:

select t.* 
from t 
where (t.personid, t.itemid) in (select personid, itemid 
           from t 
           group by personid, itemid 
           having count(*) > 1 
           ) 

和替代,我喜欢的基础上,尤金的答案,但更高效,是:

SELECT t.personid, t.ItemId, GROUP_CONCAT(t.ID) 
FROM t 
GROUP BY t.personid, t.ItemId 
HAVING COUNT(*) > 1; 

它摒弃了任何连接,如果你不介意将id作为列表而不是单独的行。

+0

谢谢你的回答。这确实有用,做我需要的。对我的表来说,这是最慢的选项。这两个都需要5到10秒,其他答案需要50ms。 – kasdega

+0

@kasdega。 。 。如果你有'personid,itemid'上的索引,所有的答案都会运行得更快。 –

+0

@GordonLinoff这是一个系统问题:在这种情况下,子查询将按行执行,而连接则不会 - 查看执行计划! –

4

像这样的东西应该做的伎俩:

SELECT P1.* 
FROM PersonItem P1 
INNER JOIN PersonItem P2 ON P2.ID <> P1.ID 
AND P2.PersonId = P1.PersonId 
AND P2.ItemId = P1.ItemId 
+0

这工作得很好。谢谢。 – kasdega

+0

这是最好的答案。 – Urbycoz

3
SELECT GROUP_CONCAT(p1.ID), p1.personid, p1.ItemId 
FROM PersonItem AS p1 
INNER JOIN PersonItem AS p2 ON 
    p1.ID<>p2.ID 
    AND p1.personid=p2.personid 
    AND p1.ItemId=p2.ItemId 
GROUP BY p1.personid, p1.ItemId 
+0

这工作得很好。谢谢。 – kasdega

+0

@GordonLinoff我为什么要?这是一个INNER JOIN,我排除了通过p1.ID <> p2.ID'的自连接 –

相关问题