2017-04-14 69 views
2
+----------+---------+---------+-----------+-----------+--------------+ 
| entry_id | item_id | stat_id | stat_type | int_value | string_value | 
+----------+---------+---------+-----------+-----------+--------------+ 
|  1 | 4255 |  10 | int  |  54 | NULL   | 
|  2 | 4255 |  16 | int  |  443 | NULL   | 
|  3 | 4255 |  56 | int  |  13 | NULL   | 
|  4 | 6544 |  10 | int  |  54 | NULL   | 
|  5 | 6544 |  56 | int  |  13 | NULL   | 
|  6 | 6544 |  16 | int  |  443 | NULL   | 
|  7 | 8570 |  56 | int  |  13 | NULL   | 
|  8 | 8570 |  10 | int  |  76 | NULL   | 
|  9 | 8570 |  72 | int  |   1 | NULL   | 
+----------+---------+---------+-----------+-----------+--------------+ 

以上是我拥有的表格的示例。 任务是为表提供一个目标“item_id”值,获取与目标具有相同行的“item_id”。使用MySQL查询查找具有匹配行的ID

在上面的示例中,提供4255的“item_id”将返回6544,在这两个“item_id”值都在三行中找到,每行另有匹配(除“entry_id”之外)。

实质上,我需要找出数据库中是否存在另一个“item_id”,即在所有方面与目标相同。如果它具有相同的行,但也可以在其他行中找到,则不会将其归类为匹配项。

作为SQL查询的一部分,可以做这种事情吗? 我目前正在C#代码中执行此操作,其中我逐一查看包含目标“item_id”的每一行,查找匹配项。这看起来效率很低。

+0

这不仅是一个有趣的问题,但它是相当的网站上的第一个问题写得很好的。 –

回答

0

假设您没有重复项(组合(item_id, stat_id, stat_type, int_value, string_value)是唯一的)并且只有string_value可以为NULL,那么您可以连接完全匹配并比较行计数(mathces的数量必须等于两者的行数项目)。

select t2.item_id 
from t t1 
join t t2 using(stat_id, stat_type, int_value) 
where t1.item_id = 4255 
    and t2.item_id <> t1.item_id 
    and t2.string_value <=> t1.string_value 
group by t1.item_id, t2.item_id 
having count(*) = (select count(*) from t where t.item_id = 4255) 
    and count(*) = (select count(*) from t where t.item_id = t2.item_id) 

演示:http://rextester.com/RIU87596

0

我认为MySQL中最简单的方法是使用group_concat()。这是一个黑客的一点点,但它应该很好地工作 - 假设你可以用NULL一点点灵活:

select t.item_id 
from (select item_id, 
      group_concat(stat_id, '|', stat_type, '|', int_value, '|', coalesce(string_value, '<NULL>' order by stat_id) as fields 
     from t 
     group by item_id 
    ) t join 
    (select item_id, 
      group_concat(stat_id, '|', stat_type, '|', int_value, '|', coalesce(string_value, '<NULL>' order by stat_id) as fields 
     from t 
     where item_id = 4255 
    ) tspecial 
    on tspecial.fields = t.fields; 

注意事项:

  • 这需要一些特殊处理NULL
  • 默认情况下,用于group_concat()的内部字符串的长度为1,024个字符。如果需要,这可以被覆盖。
  • 这假定这些字段没有分隔字符('|')。

关系解决方案有点复杂。

select i.item_id 
from (select distinct item_id from t) i cross join 
    (select stat_id, stat_type, int_value, string_value 
     from t where item_id = 4255 
    ) s left join 
    t 
    on t.stat_id = s.stat_id and 
     t.stat_type = s.stat_type and 
     t.int_value is not distinct from s.int_value and 
     t.string_value is not distinct from s.string_value 
group by i.item_id 
having count(*) = count(t.stat_id); 

这是如何工作的?它会为所有项目所需的字段生成所有统计数据。然后它执行left join以匹配其他字段中的值。聚合然后检查匹配统计数量与预期数量匹配。

其中一个优点是该版本对NULL值或分隔符不具有奇怪的限制。