使用表值参数设置基于表过滤

时间:2017-05-16 22:34:49

标签: sql sql-server

我正在寻找一种基于Set Based的方法来过滤表数据,给定一个表值参数作为UDF或SPROC的输入。

数据表定义为:

CREATE TABLE activity
(
     id int identity primary key, 
     employeeId int NOT NULL,
     stationId char(1) NOT NULL,
     type int NOT NULL
);

表值参数定义为:

CREATE TYPE activityType AS TABLE(
    stationId char(1) NOT NULL,
    type int NOT NULL
);

鉴于以下表格数据:

INSERT INTO activity
(employeeId, stationId, type)
VALUES
(100, 'A', 1), (100, 'B', 2), (100, 'C', 3),
(200, 'A', 1), (200, 'B', 2), (200, 'D', 1),
(300, 'A', 2), (300, 'C', 3), (300, 'D', 2);

我希望能够从UI中过滤给定的TVP。

示例1 :查找执行活动1 @ Station A AND Activity 2 @ Station B的所有employeeId

DECLARE @activities activityType;

INSERT INTO @activities
VALUES('A', 1),('B', 2)

应用此TVP的预期结果:

employeeId
-----------------
100
200

示例2:查找执行活动1 @ Station A,Activity 2 @ Station B和Activity 3 @ Station C

的所有employeeId
DECLARE @activities activityType;

INSERT INTO @activities
VALUES('A', 1),('B', 2),('C', 3);

应用此TVP的预期结果:

employeeId
-----------------
100

我可以通过在TVP上循环并与单独过滤的结果相交来应用此过滤器。但是,我有直觉感觉有一种使用CTE或MERGE的基于设置的方法,我现在无法解决这个问题。

3 个答案:

答案 0 :(得分:0)

对于方案1 - 您可以inner join使用表值参数本身。对于第二种情况,您可以这样做:

select distinct a.employeeId 
from #activity as a
inner join @activities as b on b.stationId = a.stationId and b.type = a.type

对于第二种情况:

   select distinct act.employeeId 
   from #activity as act 
   where act.employeeId not in (
          select distinct a.employeeId from #activity as a
          left join @activities as b on b.stationId = a.stationId and b.type = a.type
          where b.stationId is null)

答案 1 :(得分:0)

也许不是完美的解决方案,但你可以尝试下一步:

DECLARE @ExpectedActivities int

SELECT
    @ExpectedActivities = COUNT(*)
FROM
    @activities

SELECT
   *
FROM
    activity A
    INNER JOIN
    (
        SELECT
            NA.employeeId
        FROM
            activity NA
            INNER JOIN @activities FA ON FA.stationId  = NA.stationId
                AND FA.type = NA.type
        GROUP BY
            NA.employeeId
        HAVING
            COUNT(*) >= @ExpectedActivities
    ) B ON A.employeeId = B.employeeId

答案 2 :(得分:0)

这是一个没有剩余问题的关系部门。 Dwain Camps有一篇关于此的文章,提供了许多解决方案:

High Performance Relational Division in SQL Server

SELECT a.employeeId 
FROM (
    SELECT DISTINCT employeeId, stationId, type 
    FROM activity
) a
INNER JOIN @activities at
    ON a.stationId = at.stationId
    AND a.type = at.type
GROUP BY
    a.employeeId
HAVING 
    COUNT(*) = (SELECT COUNT(*) FROM @activities);

ONLINE DEMO