2017-03-12 54 views
0

SQL我有一個表TableA的,如MS-SQL
替代爲「除」與性能

TrId Status 
2345 3 
    567 3 
    567 0 
2345 0 
    99 3 
    778 0 

的情況是很少TrIds有地位3,以及0,有的有3只有些0只要。我需要找到狀態TrIds只有3
一個做的方式是:

Select TrnId From TableA Where flgStatus = 3 
EXCEPT 
Select TrnId From Tablea Where flgStatus = 0 

有超過100萬條記錄,併爲除了我沒有足夠的時間窗口,這方面的任何替代會很感激。

+1

哪種味道的SQL? (PostgreSQL,MySQL,SQL Server,...?) – Ryan

+0

可能Postgress –

+0

@Ryan:哎呀!這是Ms-squl。它現在被添加 – EetSandhu

回答

1

組合(TrnId,flgStatus)是否是唯一的?

然後,您可以切換到EXCEPT ALL,類似於UNION ALL,這可能比UNION更有效,因爲它避免了DISTINCT操作。

它訪問基表只有一次另一種解決方案:

Select TrnId 
From TableA Where flgStatus in (0,3) 
group by TrnId 
having MIN(flgStatus) = 3 
+0

這不會產生所需的結果。如果您將其更改爲「MIN(flgStatus)= 3」,儘管如此。 – Igor

+1

@Igor:當然,謝謝你指出。 – dnoeth

1

EXCEPTMINUS在這裏是正確的。然而,在一張非常大的桌子上,它並不是最佳的。

另一種方法是這樣

SELECT * 
FROM TableA 
WHERE flgStatus = 3 
AND TrnId NOT IN 
(SELECT TrnId From TableA Where flgStatus = 0) 

甚至更​​好,使用LEFT JOINIS NULL避免NOT這是一個PERF的殺手鐗:

SELECT * 
FROM TableA T3 
LEFT JOIN TableA T0 ON T3.TrnId = T0.TrnId AND T0.flgStatus = 0 
WHERE T3.flgStatus = 3 
    AND T0.TrnId IS NULL 

編輯:從伊戈爾NOT EXISTS解也是好辦法

+0

我會在星期二檢查這個表現,並讓你知道我是否必須打綠色的檢查! :) – EetSandhu

3

您可以使用NOT EXISTS

SELECT * 
FROM TableA a 
WHERE flgStatus = 3 
AND NOT EXISTS 
(SELECT TrnId From TableA b Where flgStatus = 0 AND a.TrnId = b.TrnId) 

這通常比NOT IN有更好的性能。一個好的替代方案是加入,參見@ThomasG'的答案。

+1

我很確定'JOIN'不起作用。 – Ryan

1

我會用一個簡單的group by

select trnid 
from tablea 
group by trnid 
having min(status) = max(status) and min(status) = 3; 

無論這是更快與否取決於多種因素。 。 。特別是您是否要刪除重複項以及您對數據有哪些索引。 NOT EXISTS可能會更快,如果你不關心重複,但重複消除需要工作。

+0

這個人差不多是@dnoeth的回答的兩倍。 – EetSandhu

+0

@EetSandhu。 。 。那麼你的表格中必須有其他狀態。 –

+0

是的。 0,1,3所有的所有狀態類型。爲了所有的緣故,我上面評論過。否則,它工作正常。 – EetSandhu

0

對於大型數據集的像你這樣的,使用下面的查詢可能會獲得合理的性能你想要的結果 -

SELECT ta1.TrId AS TrId 
FROM dbo.TableA AS ta1 
LEFT JOIN dbo.TableA AS ta2 ON (ta2.TrId = ta1.TrId AND ta2.[Status] != 3) 
WHERE ta2.TrId IS NULL; 

首先,自聯接通過安排所有的狀態(3或0,1創建一個表等)在同一行。過濾器

ta2.[Status] != 3 

如果狀態爲3,則在連接子句中爲ta2.TrId(或ta2。*)放置NULL。

+------+--------+------+--------+ 
| TrId | Status | TrId | Status | 
+------+--------+------+--------+ 
| 2345 |  3 | 2345 | 0  | 
| 567 |  3 | 567 | 0  | 
| 567 |  0 | 567 | 0  | 
| 2345 |  0 | 2345 | 0  | 
| 99 |  3 | NULL | NULL | 
| 778 |  0 | 778 | 0  | 
+------+--------+------+--------+ 

然後,下面的過濾器用於選擇發生NULL的行。

WHERE ta2.TrId IS NULL 

由於它是自左連接,所以左表具有除了連接條件不符合的右表值以外的所有行,但爲NULL表。

+0

我會在星期五檢查這一個的表現,並讓你知道。如果這最適合我或@dnoeth的接受答案。 – EetSandhu

+0

我之前並不知道您的狀態不是0和3.所以我更新了我的答案,並更改了聯接子句的過濾器。我也非常希望看到這個解決方案的龐大數據集之間的比較。 – Shiblu