2017-05-16 70 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謝謝。你很好地形成了你的問題。 –

相關問題