1

我在 MS-Sql 中有一个表 TableA

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

场景是少数 TrId 的状态为 3 和 0 ,有些只有 3 ,有些只有 0 。我只需要找到状态为 3 的 TrId。
其中一种方法是:

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

有超过 1 亿条记录,我没有足够的时间窗口,除非,对此的任何替代方案将不胜感激。

4

5 回答 5

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 的回答。

于 2017-03-12T09:16:19.597 回答
1

我会使用一个简单的group by

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

这是否更快取决于几件事。. . 尤其是您是否要删除重复项以及您对数据的索引。 NOT EXISTS如果您不关心重复,可能会更快,但重复消除需要工作。

于 2017-03-12T12:09:26.950 回答
1

组合是(TrnId,flgStatus)独一无二的吗?

然后你可能会切换到EXCEPT ALLUNION ALL这可能比它更有效,UNION因为它避免了 DISTINCT 操作。

另一种仅访问一次基表的解决方案:

Select TrnId 
From TableA Where flgStatus in (0,3)
group by TrnId
having MIN(flgStatus) = 3
于 2017-03-12T09:35:00.223 回答
1

EXCEPT或者MINUS是正确的事情。然而,在一张非常大的桌子上,它并不是最佳选择。

另一种选择是这样

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

甚至更好的是,使用LEFT JOINIS NULL避免NOTwhich 是性能杀手:

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 EXISTSIgor 的解决方案也是一个好方法

于 2017-03-12T09:13:53.560 回答
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

如果 Status 为 3,则在 join 子句中为 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

由于它是自 LEFT JOIN,因此左表包含所有行,但对于连接条件不符合的右表值,左表为 NULL。

于 2017-03-12T14:09:24.847 回答