获取两列中具有相同值但第三列中具有不同值的记录

时间:2019-05-17 17:59:24

标签: sql sql-server tsql

我在编写查询时遇到麻烦,该查询将返回所有记录,其中第2列的值相同但第3列的值不同。我正在寻找Item_Type和Location_ID相同但Sub_Location_ID不同的记录。

该表如下所示:

+---------+-----------+-------------+-----------------+
| Item_ID | Item_Type | Location_ID | Sub_Location_ID |
+---------+-----------+-------------+-----------------+
|       1 |     00001 |          20 |              78 |
|       2 |     00001 |         110 |             124 |
|       3 |     00001 |         110 |             124 |
|       4 |     00002 |           3 |              18 |
|       5 |     00002 |           3 |              25 |
+---------+-----------+-------------+-----------------+

我想要得到的结果看起来像这样:

+---------+-----------+-------------+-----------------+
| Item_ID | Item_Type | Location_ID | Sub_Location_ID |
+---------+-----------+-------------+-----------------+
|       4 |     00002 |           3 |              18 |
|       5 |     00002 |           3 |              25 |
+---------+-----------+-------------+-----------------+

我一直在尝试使用以下查询:

SELECT *
FROM Table1
WHERE Item_Type IN (
     SELECT Item_Type
     FROM Table1
     GROUP BY Item_Type
     HAVING COUNT (DISTINCT Sub_Location_ID) > 1
)

但是它返回所有具有相同Item_Type和不同Sub_Location_ID的记录,不是所有具有相同Item_Type AND Location_ID但具有不同Sub_Location_ID的记录。

4 个答案:

答案 0 :(得分:3)

这应该可以解决问题...

-- some test data...
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL 
BEGIN DROP TABLE #TestData; END;

CREATE TABLE #TestData (
    Item_ID INT NOT NULL PRIMARY KEY,
    Item_Type CHAR(5) NOT NULL,
    Location_ID INT NOT NULL,
    Sub_Location_ID INT NOT NULL 
    );
INSERT #TestData (Item_ID, Item_Type, Location_ID, Sub_Location_ID) VALUES
    (1, '00001',  20,  78),
    (2, '00001', 110, 124),
    (3, '00001', 110, 124),
    (4, '00002',   3,  18),
    (5, '00002',   3,  25);

-- adding a covering index will eliminate the sort operation...
CREATE NONCLUSTERED INDEX ix_indexname ON #TestData (Item_Type, Location_ID, Sub_Location_ID, Item_ID);

-- the actual solution...
WITH
    cte_count_group AS (
        SELECT 
            td.Item_ID,
            td.Item_Type,
            td.Location_ID,
            td.Sub_Location_ID,
            cnt_grp_2 = COUNT(1) OVER (PARTITION BY td.Item_Type, td.Location_ID),
            cnt_grp_3 = COUNT(1) OVER (PARTITION BY td.Item_Type, td.Location_ID, td.Sub_Location_ID)
        FROM
            #TestData td
        )
SELECT 
    cg.Item_ID,
    cg.Item_Type,
    cg.Location_ID,
    cg.Sub_Location_ID
FROM
    cte_count_group cg
WHERE 
    cg.cnt_grp_2 > 1
    AND cg.cnt_grp_3 < cg.cnt_grp_2;

答案 1 :(得分:1)

我认为您可以使用exists

select t1.*
from table1 t1
where exists (select 1
              from table1 tt1
              where tt1.Item_Type = t1.Item_Type and
                    tt1.Location_ID = t1.Location_ID and
                    tt1.Sub_Location_ID <> t1.Sub_Location_ID
             );

答案 2 :(得分:1)

Sql服务器没有向量IN,因此您可以通过一点技巧对其进行仿真。假设'#'是Item_Type

的非法字符
SELECT *
FROM Table1
WHERE Item_Type+'#'+Cast(Location_ID as varchar(20)) IN (
     SELECT Item_Type+'#'+Cast(Location_ID as varchar(20))
     FROM Table1
     GROUP BY Item_Type, Location_ID
     HAVING COUNT (DISTINCT Sub_Location_ID) > 1
);

缩小是WHERE中的表达式为non-sargable

答案 3 :(得分:1)

您可以使用exists

select t.*
from table t
where exists (select 1 
              from table t1 
              where t.Item_Type = t1.Item_Type and
                    t.Location_ID = t1.Location_ID and
                    t.Sub_Location_ID <> t1.Sub_Location_ID
             );