ADO 更新或插入缺少第二个执行分支的输出插入值

ADO Update Or Insert is missing Output Inserted Value for second Execute Branch

我正在使用带有 SQL Server 2019 和 Delphi 10.4 Update 2 的 TADOQuery。我正在尝试在一个 SQL 语句中解决更新或插入操作.

我已将列 IndexField 定义为自动递增列。

这是我的(简体)SQL服务器table:

CREATE TABLE [dbo].[Artikel]
(
    [SuchBeg] [varchar](25) NULL,
    [ArtNr] [varchar](25) NULL,
    [IndexField] [bigint] IDENTITY(1,1) NOT NULL,
    PRIMARY KEY CLUSTERED ([IndexField] ASC) 
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

简化的SQL语句:

UPDATE Artikel 
SET [SuchBeg] = 'TEST', 
    [ArtNr] = '19904.S' 
OUTPUT INSERTED.[IndexField] 
WHERE [ArtNr] = '19904.S'

IF @@ROWCOUNT = 0
INSERT INTO Artikel ([SuchBeg], [ArtNr]) 
    OUTPUT Inserted.[IndexField] 
    VALUES ('TEST', '19904.S');

Delphi 来源:

Query := TADOQuery.Create(nil);
Query.Connection := ADOConnection;
try
  Query.SQL.Text := sSqlText;
  Query.Open; // not ExecSQL; if Results are expected: Open does the Trick.
  Memo1.Lines.Add('Ado Result: '+ Query.RecordCount.ToString + ' ~ ' +  Query.Fields[0].AsString);
finally
  Query.Free;
end;

如果我点击 SQL 中的“更新部分”,我可以从查询中读取 1 行 1 字段记录集。但是,如果第二个“插入部分”被执行,我不会得到结果(0 行,1 个字段(Bigint)与 0)。

如果我在没有“if Rowcount”的情况下执行“更新”或“插入”。

如果语句在 SQL Server Management Studio 中执行,它会工作,并显示 2 个结果 Windows。前 0 行受影响,第二行具有所需值,1 行受影响。

是否可以一次性完成?

Alternative Upsert Ways 在这里...但我不想成为 SQL 服务器超级英雄。

尝试将输出存储到 table 变量,然后 return 变量。

DECLARE @Output TABLE (IndexField BIGINT);

UPDATE Artikel SET [SuchBeg] = 'TEST', [ArtNr] = '19904.S' OUTPUT INSERTED.[IndexField] INTO @Output WHERE [ArtNr] = '19904.S'
if @@ROWCOUNT = 0
INSERT INTO Artikel ([SuchBeg], [ArtNr]) Output Inserted.[IndexField] INTO @Output VALUES ('TEST', '19904.S');

SELECT * FROM @Output;

如果您只更新一行,您可以使用 OUTPUT 参数。我不确定 Delphi 那边,但 SQL 看起来像这样

Declare @IndexField Bigint;
UPDATE Artikel 
SET [SuchBeg] = 'TEST', 
    @IndexField = [IndexField] 
WHERE [ArtNr] = '19904.5'

IF @@ROWCOUNT = 0
BEGIN
    INSERT INTO Artikel ([SuchBeg], [ArtNr]) 
    VALUES ('TEST', '19904.5');

    SET @IndexField = SCOPE_IDENTITY();
END;

SELECT @IndexField;

我必须说,我没有看到将 ArtNr 列更新为相同值的意义


请注意,如果您想让此 ACID 事务符合要求,您将使用以下提示

SET XACT_ABORT ON;  -- ensures rollback

BEGIN TRAN;

UPDATE Artikel WITH (UPDLOCK, HOLDLOCK)
SET [SuchBeg] = 'TEST', 
    @IndexField = [IndexField] 
WHERE [ArtNr] = '19904.S'

IF @@ROWCOUNT = 0
BEGIN
    INSERT INTO Artikel ([SuchBeg], [ArtNr]) 
    VALUES ('TEST', '19904.S');

    SET @IndexField = SCOPE_IDENTITY();
END;

COMMIT;

SELECT @IndexField;