使用MySQL查询查找具有匹配行的ID

时间:2017-04-14 18:01:18

标签: mysql sql

+----------+---------+---------+-----------+-----------+--------------+
| 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"与目标具有相同行的。

在上面的示例中,提供" item_id" 4255将返回6544,在那两个" item_id"值可以在三行中找到,每行在其他方面相互匹配(" entry_id&#34除外)。

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

是否有可能将此类事物作为SQL查询的一部分? 我目前正在使用C#代码执行此操作,其中我遍历包含目标的每一行" item_id"一个接一个,寻找比赛。这似乎非常低效。

2 个答案:

答案 0 :(得分: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值或分隔符不具有奇怪的限制。

答案 1 :(得分:0)

假设您没有重复项(组合(item_id, stat_id, stat_type, int_value, string_value)是唯一的)且只有string_value可以为NULL,那么您可以加入完全匹配并比较行数(数学的数量必须相等)到两个项目的行数。)

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