使用tSQL计算行中不同列的数量

时间:2013-07-31 17:36:15

标签: sql sql-server tsql

我正在为我的工作完成一项任务,不幸的是,这些表的设计非常糟糕,而且我不能做太多修改结构(我们这里的一个主要程序已基于这些过时的表多年)。话虽这么说,我需要找到一种方法来使用SQL Server(TSQL)来计算给定行中不同列的数量。

实施例

我有一个包含namefieldAfieldBfieldCfieldD等列的表格 我想返回一个包含每一行的表格,返回name以及fieldA的不同列数 - fieldD

目视:

  • Jim - 1 - 3 - 4 - 6
  • John - 1 - 1 - 1 - 2
  • Jane 2 - 2 - 3 - 3

会返回

  • 吉姆 - 4
  • John - 2
  • Jane - 2

5 个答案:

答案 0 :(得分:10)

实现此目的的一种方法是通过取消数据,然后再将其分组。这使您可以使用count(distinct)

select name, count(distinct val)
from t
unpivot (val for col in (FieldA, FieldB, FieldC, FieldD)) unpvt
group by name;

但是,最有效的方法是将所有处理保留在一行 - 没有joingroup byunion。假设没有值为NULL,则以下内容适用于4列:

select name,
       4 - ((case when FieldA in (FieldB, FieldC, FieldD) then 1 else 0 end) +
            (case when FieldB in (FieldC, FieldD) then 1 else 0 end) +
            (case when FieldC in (FieldD) then 1 else 0 end)
           )
from t;

即,从列总数开始。每当一列与以后的列相似时,减去1。最后一个条件确保重复项不会被计算多次。

答案 1 :(得分:6)

DECLARE @x TABLE
(
  Name VARCHAR(32),
  A VARCHAR(32),
  B VARCHAR(32),
  C VARCHAR(32),
  D VARCHAR(32)
);

INSERT @x VALUES
('Jim', 1,3,4,6),
('John',1,1,1,2),
('Jane',2,2,3,3);

SELECT Name, NumCols = COUNT(DISTINCT x) 
FROM @x AS x
UNPIVOT (x FOR y IN (A,B,C,D)) AS up
GROUP BY Name
ORDER BY NumCols DESC; 

答案 2 :(得分:4)

您可以使用UNPIVOT运算符将列转换为行,然后计算不同的值:

select c_name
     , count(distinct val) as distinct_vals
     , count(val)          as total_vals
  from ( select c_name
              , val
           from t1
         unpivot(
             val for col in(col1, col2, col3, col4) 
          ) unpvt
        ) s
group by c_name

结果:

C_NAME  DISTINCT_VALS   TOTAL_VALS
Jane    2               4
Jim     4               4
John    2               4

SQLFIDDLE Demo

答案 3 :(得分:4)

又一种方法:

SELECT
   Name,
   Cnt = (SELECT COUNT(DISTINCT V) FROM (VALUES (A), (B), (C), (D)) AS v (V))
FROM atable
;

使用SQL Server 2008语法(VALUES行构造函数)。它可以通过将VALUES (A), (B), ...替换为SELECT A UNION ALL SELECT B UNION ALL ...来适应早期版本。

答案 4 :(得分:0)

Select Name,Count(*) From
(select Name,FieldA from test10
Union
select Name,FieldB from test10
union
select Name,FieldC from test10
Union
select Name,FieldD from test10)as a
Group by name