2017-05-16 67 views
2

我正在查看是否存在一个基于集合的方式来过滤表数据给定表值参数作为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:从应用此TVP查找谁执行活动1 @站A中的所有雇员和活动2 @ B站

DECLARE @activities activityType; 

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

预期结果:

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

实施例2:查找所有进行过的活动1 @活动1 @活动场所A,活动2 @活动场所B和活动3 @活动场所C

从应用此TVP
DECLARE @activities activityType; 

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

预期结果:

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

我可以通过循环在TVP和个别地过滤的结果交叉应用此过滤器。然而,我有直觉认为有一种使用CTE或MERGE的Set Based方法,目前我无法包裹头部。

+0

那么,哪里是你的问题? – Sami

+0

什么是适当的基于集合的SQL查询来过滤活动表数据,给定一个表值参数和任意数量的activityType行。有效地,我试图创建一个函数FindEmployeeByStationActivities(@activities activityType READONLY) – UbuntuUser

回答

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 
+0

我相信如果进行两次相同的活动,这将有问题。例如:(100, 'A',1),(100, 'A',1),(100, 'B',2),(100, 'C',3)在数据表中。 – UbuntuUser

+0

这个问题没有提及有关重复活动的业务规则东西。您始终可以使用不同的分区,等等,以满足您更精细的要求。 – DanielCuadra

+0

重复活动的量作为提供活性计数至少一次确实是可忽略的,只要。我相信这种做法可能是最好的路径。我会在尝试后回报。 – UbuntuUser

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) 
+0

不幸的是,OR谓词的数量取决于TVP中的任意行数。这可以通过动态sql来完成,但我更愿意不打开那些蠕虫。 – UbuntuUser

+0

我认为这个连接工作得很好。你尝试过吗?没关系,只适用于第一个场景.. – NoSaidTheCompiler

+0

@UbuntuUser - 请更新。我认为这是有效的。请让,我知道,如果有问题,因为我想这个解决以及哈哈 – NoSaidTheCompiler

0

这是一个没有剩余问题的关系部门。德韦恩营大约有这与一些解决方案的文章:

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

+1

谢谢。这是最有意义的答案。我很欣赏您的答案中的教学法以及关于此主题的高度翔实的文章。 – UbuntuUser

+0

@UbuntuUser谢谢。你很好地形成了你的问题。 –

相关问题