计算 distinct 和 join over distinct 之间的差异

Posted

技术标签:

【中文标题】计算 distinct 和 join over distinct 之间的差异【英文标题】:Count difference between distinct and join over distinct 【发布时间】:2014-11-29 17:21:46 【问题描述】:

如何计算不同行的数量减去对这些相同不同行的连接?

如果用户对提交的行没有权限,我需要在触发器之后引发错误。我可以在两个语句中做到这一点,但这似乎效率低下。

DECLARE @AccessibleCount INT =
(
    SELECT
        COUNT(DISTINCT i.[ParentId])
    FROM
        inserted i
    INNER JOIN [SuperSecret].[Parent] AS p ON
        p.[Id] = i.[ParentId] AND
        p.[LockedBy] = @UserId
);

DECLARE @ActualCount INT = (SELECT COUNT(DISTINCT [ParentId]) FROM inserted);
IF (@AccessibleCount <> @ActualCount)
BEGIN
    RAISERROR(...);
    ROLLBACK TRANSACTION;
END

出于性能考虑,我似乎应该对不同的inserted.ParentId 使用子查询来计算这两个计数。我尝试了以下方法,但结果是“无效的对象名称'i'。”

DECLARE @ActualMinusAccessible INT =
(
    SELECT
        COUNT(*)
            -
        (
            SELECT
                COUNT(*)
            FROM
                i
            INNER JOIN [SuperSecret].[Parent] AS p ON
                p.[Id] = i.[ParentId] AND
                p.[LockedBy] = @UserId
        )
    FROM
        (
            SELECT DISTINCT [ParentId] FROM inserted
        ) AS i
);

IF (@ActualMinusAccessible <> 0)
BEGIN
    RAISERROR (...);
    ROLLBACK TRANSACTION;
END

【问题讨论】:

【参考方案1】:

如果没有错,如果[ParentId]插入,而[SuperSecret].[Parent] 表中不存在,您想Raise Error。尝试像这样更改您的 SQL 查询。

IF EXISTS (SELECT 1
           FROM   inserted i
           WHERE  NOT EXISTS (SELECT 1
                              FROM   [SuperSecret].[Parent] a
                              WHERE  i.[ParentId] = a.[ParentId] AND a.[LockedBy] = @UserId))
  BEGIN
      RAISERROR (...);
      ROLLBACK TRANSACTION;
  END 

IF (SELECT Count(DISTINCT [ParentId]) - (SELECT Count(DISTINCT i.[ParentId])
                                         FROM   inserted i
                                                INNER JOIN [SuperSecret].[Parent] AS p
                                                        ON p.[Id] = i.[ParentId]
                                                           AND p.[LockedBy] = @UserId)
    FROM   inserted) <> 0
  BEGIN
      RAISERROR (...);
      ROLLBACK TRANSACTION;
  END 

【讨论】:

@user1546077 - 是的,你不能在那里引用别名 (i),这是错误的。尝试执行我的答案 谢谢,第一个查询的实际执行计划比第二个要好。第二个查询的实际执行计划与原始查询类似,但在某些(很多?)情况下可能会更好。

以上是关于计算 distinct 和 join over distinct 之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server count() over() with distinct

分区函数 COUNT() OVER 可能使用 DISTINCT

论文精读《Random Sampling over Joins Revisited》

count(distinct) over (partition by... 在 Oracle SQL 中不起作用

HIVE-----count(distinct ) over() 无法使用解决办法

left join 需要distinct吗