【问题标题】:ADO Update Or Insert is missing Output Inserted Value for second Execute BranchADO 更新或插入丢失第二个执行分支的输出插入值
【发布时间】:2021-11-24 18:08:43
【问题描述】:

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

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

这是我的(简化的)SQL Server 表:

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');

德尔福来源:

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 中是 Executet,则它可以工作,并显示 2 个结果窗口。受影响的前 0 行和第二个具有所需值的行和受影响的 1 行。

可以一次性完成吗?

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

【问题讨论】:

    标签: sql-server delphi ado


    【解决方案1】:

    尝试将输出存储到表变量中,然后返回该变量。

    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;
    

    【讨论】:

    • 最后我使用了 Charlieface 和 RoberT 答案的组合。这是开箱即用的作品。但是如果没有这个答案中的声明和选择部分,我将找不到我的解决方案......谢谢你们俩
    【解决方案2】:

    如果您只更新一行,您可以使用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;
    

    【讨论】:

    • 谢谢,我综合使用了 Charlieface 和 RoberT 的答案。我编辑了第一个在 ADO 下工作的 SQL。它需要@IndexField 的声明和选择。谢谢你们俩
    猜你喜欢
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 2020-04-27
    • 2015-11-16
    • 2017-07-05
    • 1970-01-01
    相关资源
    最近更新 更多