使用SQL在数据组中查找缺失值

时间:2016-09-16 21:04:31

标签: sql sql-server database report

最近我需要根据以下事实生成报告:

TableA具有以下2列UserID和DocumentType

我已经提供了一份强制性的'文档类型:Type1,Type2,Type3和I需要返回每个没有这三种类型的UserID以及它们缺少的类型。

例如,如果TableA包含以下行

12  Type1
12  Type2
12  Type4
13  Type1
13  Type2
13  Type3
14  Type1
15  Type6
15  Type7
15  Type8

然后理想情况下输出将是:

12 Type3
14 Type2, Type3
15 Type1, Type2, Type3

理想情况下,生成结果的查询应该能够处理多达数千万条记录。

我们最近使用SQL Server 2012实现了一个类似问题的解决方案(比这更复杂一点)。在多个表中获取完整报告需要3分半钟,总共有大约400万条记录。我们想知道是否有更好的想法可以更快地做到这一点。

请随意分享您的想法,以解决此问题。

谢谢! :)

4 个答案:

答案 0 :(得分:1)

这是FOR XML路径连接方法:

equals()

我相信检查大型数据集的条件聚合查询可能会有更好的性能。

条件聚合

CREATE TABLE TableA (ID INT, TypeCol CHAR(5));
INSERT INTO TableA (ID,TypeCol) VALUES  (12,'Type1')
,(12,'Type2')
,(12,'Type4')
,(13,'Type1')
,(13,'Type2')
,(13,'Type3')
,(14,'Type1')
,(15,'Type6')
,(15,'Type7')
,(15,'Type8')

;WITH cteRequiredTypes AS (
    SELECT 'type1' as TypeCol
    UNION ALL
    SELECT 'type2'
    UNION ALL
    SELECT 'type3'
)

, cteTableAIds AS (
    SELECT DISTINCT Id
    FROM
       TableA
)

, cteMissingTypes AS (
    SELECT
       i.ID
       ,r.TypeCol
    FROm
       cteRequiredTypes r
       CROSS JOIN cteTableAIds i
       LEFT JOIN TableA a
       ON r.TypeCol = a.TypeCol
       AND i.ID = a.ID
    WHERE
       a.ID IS NULL
)


SELECT
    DISTINCT a.ID
    ,STUFF(
        (SELECT ',' + TypeCol
        FROM
            cteMissingTypes t
        WHERE t.ID = a.ID
        FOR XML PATH(''))

        ,1,1,'')
FROM
    cteMissingTypes a

答案 1 :(得分:0)

简单方法

SELECT DISTINCT UserID 
FROM your_table

EXCEPT

(
  SELECT UserID 
  FROM your_table
  WHERE DocumentType = ('Type1')

  UNION

  SELECT UserID 
  FROM your_table
  WHERE DocumentType = ('Type2')

  UNION

  SELECT UserID 
  FROM your_table
  WHERE DocumentType = ('Type3')
)

在规则中不能比这更精确 - 所以你的编译器会查看索引等并进行优化。

除非有部分问题,否则你没有告诉我们。

答案 2 :(得分:0)

我认为你需要这样的东西

select x2.*
(select *
from (select distinct UserID from [table])x
cross join  
(select 'type1' DocumentType  union 
select 'type2'  union 
select 'type3' ) y
) x2
left join [table] y2
on y2.UserID = x2.UserID
and y2.DocumentType = x2.DocumentType
where y2.DocumentType is null 
order by x2.UserID

答案 3 :(得分:0)

<强> DEMO

WITH 
base ([DocumentType]) as (
    SELECT 'Type1' UNION ALL
    SELECT 'Type2' UNION ALL
    SELECT 'Type3'
),
users as (
    SELECT DISTINCT [userID]
    FROM Table1 t    
),
pairs as ( 
    SELECT *
    FROM users, base
)    
SELECT p.userID, p.[DocumentType], t.[DocumentType]
FROM pairs p 
LEFT JOIN Table1 t
       ON p.[DocumentType] = t.[DocumentType]
      AND p.[userID] = t.[userID]
WHERE t.[DocumentType] IS NULL   

输出

enter image description here