用 CASE WHEN NOT EXISTS 设置参数值总是出来 0

Set parameter value with CASE WHEN NOT EXISTS always comes out to 0

我有一个参数 (@noMatch int output),我根据在下面的存储过程中找到的 CASE 为其赋值:

ALTER PROCEDURE [dbo].[p_trips_non_aggregate_insert]
     @trips u_trips_non_aggregate readonly, 
     @rowCount int OUTPUT, 
     @noMatch int OUTPUT
WITH RECOMPILE
AS
    BEGIN TRANSACTION
    SET NOCOUNT ON

    INSERT INTO [dbo].[trips_non_aggregate]
        ([LøyvehaverID], [KjøretøyID], [Ordrenummer], [c], [År], [Måned], [Betaling (brutto)], [Betaling (netto)], [LøyvehaverFakturaID], [IsProcessed], [RowIsChecked])
        
        SELECT DISTINCT 
            [LøyvehaverID], [KjøretøyID], [Ordrenummer], [c], [År], [Måned], [Betaling (brutto)], [Betaling (netto)], [LøyvehaverFakturaID], [IsProcessed], [RowIsChecked]
        FROM 
            @trips AS o
        WHERE 
            [IsProcessed] = '0'
            AND NOT EXISTS (SELECT [Ordrenummer]
                            FROM [dbo].[trips_non_aggregate] AS i
                            WHERE i.[Ordrenummer] = o.[Ordrenummer])

        SET @rowCount = @@ROWCOUNT

        SET @noMatch = 
            CASE WHEN NOT EXISTS
                (SELECT [LøyvehaverID]
                    FROM [dbo].[trips_non_aggregate] AS i
                    INNER JOIN [license_holder] AS o ON i.[LøyvehaverID] = o.[Foretaksnavn])
            THEN 1 ELSE 0
        END

    UPDATE [dbo].[trips_non_aggregate]
    SET [Betaling (netto)] = (SELECT [Betaling (brutto)] / ([MVAsats] / 100 + 1)
                              FROM [tblMVAkoder]
                              WHERE [ID] = 'MVAkode2')

    UPDATE [dbo].[trips_non_aggregate]
    SET [RowIsChecked] = (SELECT [RowIsChecked] = 0)

    COMMIT TRANSACTION

这样当我插入我的数据库时,我能够标记 ColumnA 中不存在于 ColumnB 中的任何条目。但是当我用假数据测试时,结果总是 0.

为什么会这样?

这是我在 C# 中检查其值的方式:

if (Convert.ToInt32(cmd.Parameters["@noMatch"].Value) == 1) 
{
    // do something
}

参数方向是否配置得像

    cmd.Parameters.Add("@noMatch", SqlDbType.Int);  
    cmd.Parameters["@noMatch"].Direction = ParameterDirection.Output; 

看起来您正在进行某种预检检查,这样如果一条或多条传入的 u_trips_non_agg 记录没有许可证持有人,您根本不会从批次中插入任何数据.我们可以在插入之前检查:

ALTER PROCEDURE [dbo].[p_trips_non_aggregate_insert]
     @trips u_trips_non_aggregate readonly, 
     @rowCount int OUTPUT
WITH RECOMPILE
AS

    IF EXISTS (
      SELECT null FROM @trips t 
      WHERE NOT EXISTS (
        SELECT null FROM license_holder lh WHERE t.[LøyvehaverID] = lh.[Foretaksnavn]
      )
    ) 
      THROW 51000, 'At least one of the records being inserted does not have a related licence holder record', 1;
    


    BEGIN TRANSACTION
    SET NOCOUNT ON

    INSERT INTO [dbo].[trips_non_aggregate]
        ([LøyvehaverID], [KjøretøyID], [Ordrenummer], [c], [År], [Måned], [Betaling (brutto)], [Betaling (netto)], [LøyvehaverFakturaID], [IsProcessed], [RowIsChecked])
        
        SELECT DISTINCT 
            [LøyvehaverID], [KjøretøyID], [Ordrenummer], [c], [År], [Måned], [Betaling (brutto)], [Betaling (netto)], [LøyvehaverFakturaID], [IsProcessed], [RowIsChecked]
        FROM 
            @trips AS o
        WHERE 
            [IsProcessed] = '0'
            AND NOT EXISTS (SELECT [Ordrenummer]
                            FROM [dbo].[trips_non_aggregate] AS i
                            WHERE i.[Ordrenummer] = o.[Ordrenummer])

        SET @rowCount = @@ROWCOUNT

        SET @noMatch = 
            CASE WHEN NOT EXISTS
                (SELECT [LøyvehaverID]
                    FROM [dbo].[trips_non_aggregate] AS i
                    INNER JOIN [license_holder] AS o ON i.[LøyvehaverID] = o.[Foretaksnavn])
            THEN 1 ELSE 0
        END

    UPDATE [dbo].[trips_non_aggregate]
    SET [Betaling (netto)] = (SELECT [Betaling (brutto)] / ([MVAsats] / 100 + 1)
                              FROM [tblMVAkoder]
                              WHERE [ID] = 'MVAkode2')

    UPDATE [dbo].[trips_non_aggregate]
    SET [RowIsChecked] = (SELECT [RowIsChecked] = 0)

    COMMIT TRANSACTION

一个 EXISTS returns true 或 false 取决于查询是否 returns 任何行。选择什么数据并不重要; EXISTS 只关心是否有任何行。你可以想象它一找到就停止,所以最好不要 运行 大量的百万行查询只是为了知道是否有一行

我们实际上使用了两次,一次是内部的,一次是外部的:

  SELECT null FROM @trips t 
  WHERE NOT EXISTS (
    SELECT null FROM license_holder lh WHERE t.[LøyvehaverID] = lh.[Foretaksnavn]
  )

第一个到运行的概念在里面:

SELECT null FROM license_holder lh WHERE t.[LøyvehaverID] = lh.[Foretaksnavn]

这是与外部协调的,你可以想象它的工作方式:

For `t.[LøyvehaverID]` = 1
SELECT null FROM license_holder lh WHERE 1 = lh.[Foretaksnavn]

For `t.[LøyvehaverID]` = 2
SELECT null FROM license_holder lh WHERE 2 = lh.[Foretaksnavn]

等等;基本上,对于外部 table @trips 中的每一行,检查 licence_holder 中是否有一行使得 @trips.[LøyvehaverID] 等于 licence_holder.[Foretaksnavn].

如果有 行,则返回 null。如果 不是 行,那么 0 行是 returns,这就是 NOT EXISTS 所依据的。也就是说,这个结构:

  FROM @trips t 
  WHERE NOT EXISTS (
    SELECT null FROM license_holder lh WHERE t.[LøyvehaverID] = lh.[Foretaksnavn]
  )

将查找没有匹配 licence_holder 行的所有 @trips


包含在另一个 EXISTS 中的所有内容,一旦找到至少一个“没有 licence_holder 行的 @trips 行”的情况,它就会有效地停止查找

一共是:

EXISTS (
  SELECT null FROM @trips t 
  WHERE NOT EXISTS (
    SELECT null FROM license_holder lh WHERE t.[LøyvehaverID] = lh.[Foretaksnavn]
  )
) 

表示:

@trips 中有一行,而许可证持有者中没有匹配的行


如果是这种情况,然后我们关闭它以抛出异常