用于匹配多行重复项的SQL

时间:2016-04-29 15:54:19

标签: sql

我有一个像这样的表格设置:

id | key | val
1  |  a  |  1
1  |  b  |  2
2  |  a  |  3
2  |  b  |  4

其中每个id可以有许多与之关联的键/值对。我正在尝试编写一个查询,查找2个id有一组重复的键/值对的情况,我可以在其中指定要查找的键。例如,在下表中:

id | key | val
1  |  a  |  1  <
1  |  b  |  2  <
1  |  c  |  9
2  |  a  |  3
2  |  b  |  4
3  |  a  |  1  <
3  |  b  |  2  <
3  |  c  |  5

如果我指定了a和b,那么查询将返回上面的标记行。到目前为止,我有以下查询:

select * 
  from MY_TABLE inner join 
         (select id 
            from MY_TABLE 
           where key = 'a' 
        group by val 
          having count(val) > 1) T1 on T1.val = MY_TABLE.val and MY_TABLE.key = 'a'

如果我只是根据单个键查找重复项,那么效果很好,但不能用于倍数。有没有人有关于如何修改上述查询的建议,以便我可以指定2个键而不只是1?

编辑:我尝试过的事情

以下查询接近(来自Max Sorin的回答):

select a.* 
  from MY_TABLE a inner join 
         (select key,val 
            from MY_TABLE 
           where key in ('a','b') 
        group by key,val 
          having count(val) > 1) b on b.val = a.val and b.key = a.key

但不管id如何,都只给我重复。更具体地说,我已经展示了以下差异:

With below table       I want this      But this query gives me this
id | key | val        id | key | val        id | key | val
1  |  a  |  1         1  |  a  |  1         1  |  a  |  1 
1  |  b  |  2         1  |  b  |  2         1  |  b  |  2
1  |  c  |  9         3  |  a  |  1         3  |  a  |  1
2  |  a  |  3         3  |  b  |  2         3  |  b  |  2
2  |  b  |  4                               4  |  b  |  2
3  |  a  |  1                               5  |  a  |  1
3  |  b  |  2                               6  |  b  |  2
3  |  c  |  5
4  |  b  |  2
5  |  a  |  1
6  |  b  |  2

Double Edit:

我被要求提供一个更具体的例子,所以在这里。假设我想找到具有相同“Key”和“Age”键值的所有对象。如果我有下表:

id | key  | value
1  | Name | 'John' <-- These rows
1  | Age  | '25'   <--
1  | Job  | 'Farmer'
2  | Name | 'Steve'
2  | Age  | '30'
3  | Name | 'John' <-- and these rows would be returned
3  | Age  | '25'   <--
3  | Job  | 'Plumber'
4  | Name | 'John' <-- But not either of these rows, because Age is different.
4  | Age  | '26'   <--

2 个答案:

答案 0 :(得分:4)

您可以在JOIN中通过将表连接到自身来执行此操作:

SELECT a.id, b.id, a.key, a.val
FROM MY_TABLE A
INNER JOIN MY_TABLE B on B.key = A.key and B.val = A.val and A.id <> B.id

然后,您可以添加WHERE B.key =WHERE B.Key IN()以根据自己的喜好缩小搜索结果。

修改

看到您的新结构,上述内容无法满足您的需求。一种解决方案是使用两个子类,一个用于name,另一个用于age

SELECT *
FROM #mytable
WHERE [key] in ('name', 'age')
AND id in (
   SELECT a.id
   FROM #mytable a
   INNER JOIN #mytable B on B.[key] = A.[key] and B.value = A.value 
                        and a.[key] = 'name' and A.id <> B.id)
AND id in (
   SELECT a.id
   FROM #mytable a
   INNER JOIN #mytable B on B.[key] = A.[key] and B.value = A.value 
                        and a.[key] = 'age' and A.id <> B.id)

答案 1 :(得分:1)

测试数据

CREATE TABLE #mytable(id INT, [key] VARCHAR(10), value VARCHAR(50))

INSERT INTO #mytable
        ( id, [key], value )
VALUES  
(1  ,'Name', 'John'),
(1  ,'Age', '25'),
(1  ,'c', '9'),
(2  ,'Name', 'Bob'),
(2  ,'Age', '4'),
(3  ,'Name', 'John'),
(3  ,'Age', '25'),
(3  ,'c', '5'),
(4  ,'Name', 'Samuel'),
(4  ,'Age', '25'),
(5  ,'Name', 'John'),
(5  ,'Age', '36')

透视表将保存每个Name-Age对的单行结果:

CREATE TABLE #pivoted (id int, Name VARCHAR(50), Age VARCHAR(10)) 
INSERT INTO #pivoted
        ( id, Name, Age )

SELECT pv.id, pv.Name, pv.Age  
    FROM (SELECT id, [key], value
    FROM #mytable
    WHERE [key] IN ('Name', 'Age')) src

    PIVOT (MAX(value) FOR [Key] IN ([Name], [Age])) AS pv

数据透视功能会丢弃未使用的密钥,并将属于单个ID的垂直值列表转换为列。

我们正在寻找这个新表格中具有相同名称 - 年龄对的所有行,而不是相同的ID来查找重复的人。

SELECT a.*
FROM #pivoted a
JOIN #pivoted b ON b.Age = a.Age AND b.Name = a.Name        
                AND b.id <> a.id

DROP TABLE #mytable
DROP TABLE #pivoted

我认为架构的设计方式是允许用户在不向表添加列的情况下向数据添加维度。如果我想存储约翰的身高,我只需添加这一行:1, 'Height', '189cm'