【问题标题】:Insert value with select statement, or if it doesn't exist insert new value使用 select 语句插入值,或者如果它不存在则插入新值
【发布时间】:2018-11-13 19:36:28
【问题描述】:

我正在尝试在 SQL Server 中执行一个查询,在该查询中我更新了一行,如果它不存在,则创建一行。这很好用,但在我的 Insert 语句中创建新行时,我需要从该表中为 _idref uniqueidentifier 选择一个值。

我遇到的情况是,如果选择没有返回可能的值,我需要使用 NEWID() 添加一个新的唯一标识符。

这是我的查询:

DECLARE @LGRACT BIGINT
DECLARE @SUBACT BIGINT
DECLARE @AMOUNT DECIMAL(12,2)
DECLARE @PostYear SMALLINT
DECLARE @PostMonth TINYINT

SET @PostYear = 2018
SET @PostMonth = 12
SET @LGRACT = 6000
SET @SUBACT = 200
SET @AMOUNT = 2000.00

UPDATE [Services Copy].dbo.lgrbal 
SET balance = ((SELECT balance 
                FROM [Services Copy].dbo.lgrbal
                WHERE lgract = @LGRACT 
                  AND postyr = @PostYear 
                  AND actprd = @PostMonth) + @AMOUNT) 
WHERE lgract = @LGRACT 
  AND postyr = @PostYear 
  AND actprd = @PostMonth

IF @@ROWCOUNT = 0
    INSERT INTO [Services Copy].dbo.lgrbal (_idnum, _idref, lgract, postyr, actprd, balance)
    VALUES (NEWID(),
            (SELECT TOP 1 _idref 
             FROM [Services Copy].dbo.lgrbal 
             WHERE lgract = @LGRACT 
               AND postyr = @PostYear) 
             WHERE NOT EXISTS NEWID()),
       @LGRACT, @PostYear, @PostMonth, @AMOUNT)

您可以在INSERT INTO VALUES 部分看到,我正在为帐户和年份返回的_idref 执行select top 1。

如果是 1 月,则不会存储其他记录,并且我没有返回 _idref。

在这种情况下,我只需将选择替换为NEWID()。

【问题讨论】:

标签: sql sql-server sql-update sql-insert


【解决方案1】:

正如@Felipe-Martins 评论的那样,MERGE 语句可能会使事情变得更容易一些。

MERGE 没有明确解决您关于动态重用现有 _idref 或通过 newid() 生成新 _idref 的具体问题,但通过在子查询周围包装 isnull() 调用很容易解决。

可能有更好的解决方案,但在您发布后的第一个小时内没有太多活动,所以我想我会保存这篇文章而不是将其丢弃以防万一。

declare @LGRACT bigint
declare @SUBACT bigint
declare @AMOUNT decimal(12,2)
declare @PostYear smallint
declare @PostMonth tinyint
set @PostYear=2018
set @PostMonth=12
set @LGRACT = 6000
set @SUBACT = 200
set @AMOUNT = 2000.00

MERGE [Services Copy].dbo.lgrbal AS target  
USING (SELECT @LGRACT, @AMOUNT, @PostYear, @PostMonth) AS source 
      (lgract, amount, postyr, actprd)  
ON (
    target.lgract = source.lgract and 
    target.postyr = source.postyr and
    target.actprd = source.actprd
)  
WHEN MATCHED THEN   
    UPDATE SET target.Balance = target.Balance + source.amount
WHEN NOT MATCHED THEN
    INSERT (
        _idnum, 
        _idref, 
        lgract, 
        postyr, 
        actprd, 
        balnce
    )  
    VALUES (
        newid(),
        isnull(
            (select top 1 _idref 
            from [Services Copy].dbo.lgrbal 
            where lgract=@LGRACT and postyr=@PostYear), 
            newid()),
        source.lgract, 
        source.postyr, 
        source.actprd, 
        source.balance
    ) 

【讨论】:

  • 谢谢。我之前没有使用过 Merge,但是在看到这个之后,我会在其他我知道它会起作用的场景中更多地使用它。
  • 对 MERGE 非常小心。 mssqltips.com/sqlservertip/3074/…
【解决方案2】:

不确定这是否是行业标准,但我将这种类型的操作称为“Upsert”。

这是我在存储过程中的典型处理方式。

IF (EXISTS(SELECT * FROM TABLE_NAME WHERE IdColumn = @IdParameter)) BEGIN   
    -- UPDATE 
    UPDATE TABLE_NAME 
    SET columns appropriately
    WHERE IdColumn = @IdParameter 
END 
ELSE 
BEGIN   
-- INSERT
    SET @IdParameter= NEWID();

    INSERT INTO TABLE_NAME 
    SELECT @IdParameter,
    @OtherParams

END

EXEC usp_Select_YourObject @IdParameter; -- other stored proc that handles the object to be returned. ;

显然,这更像是一种通用方法。你的情况仍然适用。我会先查询该表以查看该行是否存在。如果是这样,请相应地更新它。如果没有,请插入一个具有新 ID 的新 ID。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2012-06-07
    • 2012-05-21
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    相关资源
    最近更新 更多