使用select语句插入值,或者如果不存在,则插入新值

时间:2018-11-13 19:36:29

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

我正在尝试在SQL Server中执行查询,在其中更新一行,如果该行不存在,请创建一行。效果很好,但是在我用于创建新行的插入语句中,我需要从该表中为_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部分中看到,我正在为返回的帐户和年份的select top 1_idref

如果是1月,将不会存储其他记录,也不会返回_idref

在这种情况下,我只需要用NEWID()替换选择即可。

2 个答案:

答案 0 :(得分: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
    ) 

答案 1 :(得分:0)

不确定这是否是行业标准,但是我将这种类型的操作称为“ 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。