我正在寻找一种基于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
的所有employeeIdDECLARE @activities activityType;
INSERT INTO @activities
VALUES('A', 1),('B', 2),('C', 3);
应用此TVP的预期结果:
employeeId
-----------------
100
我可以通过在TVP上循环并与单独过滤的结果相交来应用此过滤器。但是,我有直觉感觉有一种使用CTE或MERGE的基于设置的方法,我现在无法解决这个问题。
答案 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);