选择列值唯一的所有行

时间:2017-02-01 14:50:21

标签: tsql sql-server-2012 distinct-values

表T包含列n00,n01,n01,...,n99,所有整数。

我需要从这个表中选择所有行,其中n00 ... n99值在每一行中都是唯一的。

列数较少的示例:

columns: n0, n1, n2
row 1:   10, 20, 30
row 2:   34, 45, 56
row 3:   12, 13, 12
row 4:   31, 65, 90

我需要select语句返回第1,2和4行而不是3(第3行包含12的非唯一值,因此将其过滤掉)。

有效地我需要实现这个:

select *
from t
where 
      n00 <> n01 and n00 <> n02 and ... and n00 <> n99
  and n01 <> n02 and n01 <> n03 and ... and n01 <> n99
  and n02 <> n03 and n02 <> n04 and ... and n02 <> n99
  ...
  and n97 <> n98 and n97 <> n99
  and n98 <> n99

...但是&#34;更聪明&#34;阻止。

欢迎任何提示。

2 个答案:

答案 0 :(得分:2)

使用CROSS APPLY和一点XML的更动态的方法。我应该添加UNPIVOT会更高效,但这种方法的表现非常可观,而且你没有识别所有领域。

您会注意到我添加了ID字段。如果不存在,可以从CROSS APPLY C中删除。我添加了ID以证明可以从逻辑中排除其他字段。

Declare @YourTable table (id int,n0 int, n1 int, n2 int)
Insert Into @YourTable values
(1,10, 20, 30),
(2,34, 45, 56),
(3,12, 13, 12),
(4,31, 65, 90)

Select A.*
 From  @YourTable A
 Cross Apply (Select XMLData=cast((Select A.* For XML Raw) as xml))  B
 Cross Apply (
               Select Cnt=count(*),Uniq=count(Distinct Value)
                From (
                        Select ID     = r.value('@id','int')                                     -- case sensitive
                              ,Item   = attr.value('local-name(.)','varchar(100)')
                              ,Value  = attr.value('.','varchar(max)') 
                         From  B.XMLData.nodes('/row') as A(r)
                         Cross Apply A.r.nodes('./@*') AS B(attr)
                         Where attr.value('local-name(.)','varchar(100)') not in ('id','excludeotherfields')  -- case sensitive
                     ) U
             ) C
 Where Cnt=Uniq

返回

id  n0  n1  n2
1   10  20  30
2   34  45  56
4   31  65  90

如果它对可视化有帮助,那么XML部分将生成以下内容

enter image description here

答案 1 :(得分:2)

您也可以使用UNPIVOT:

DECLARE @t TABLE(n0 int, n1 int, n2 int);
INSERT INTO @t VALUES (10, 20, 30), (34, 45, 56), (12, 13, 12), (31, 65, 90);

WITH cteRows AS(
  SELECT ROW_NUMBER() OVER (ORDER BY n0, n1, n2) rn, *
             FROM @t
),
cteUP AS(
  SELECT rn, rn_val
    FROM cteRows
  UNPIVOT(
    rn_val FOR rn_vals IN(n0, n1, n2)
  ) up
),
cteFilter AS(
  SELECT rn, rn_val, count(*) anz
    FROM cteUP
    GROUP BY rn, rn_val
    HAVING count(*) > 1
)
SELECT *
  FROM cteRows
  WHERE rn NOT IN (SELECT rn FROM cteFilter)