使用更新或插入语句添加到整数值

Adding to integer value with update or insert statement

我正在尝试在 Firebird 2.5 中创建一个 SQL 语句,以便在记录存在时通过添加来更新整数数量,或者只是插入一个新行。我似乎找不到关于添加到某个数量(如果它已经存在)的具体问题的真正答案。

我能想到的SQL是这样的:

UPDATE OR INSERT INTO Pencils(Number, Location, Quantity)
VALUES('12345678/90', 'TOP', 20)
MATCHING(Number, Location);

所以如果有匹配的记录我想在实际20个数量的基础上增加一定数量

就像我对 UPDATE 语句所做的那样:

UPDATE Pencils SET Quantity = Quantity + 20 WHERE Number = '12345678/90' 

是否可以用UPDATE OR INSERT语句达到这样的结果,或者有其他方法吗? . .

编辑: 与 IBExpert / Delphi

一起使用参数的查询的解决方案
MERGE INTO Pencils AS Dest
USING (SELECT CAST(:myNumb as varchar(30))  AS Number,
              CAST(:myLoca as varchar(10))  AS Location,
              CAST(:myQuan as integer)  AS Quantity
        FROM RDB$DATABASE) Src
    ON (Dest.Number = Src.Number AND Dest.Location = Src.Location)
WHEN MATCHED THEN
   UPDATE SET Dest.Quantity = Dest.Quantity + Src.Quantity
WHEN NOT MATCHED THEN
   INSERT (Number, Location, Quantity) VALUES (Src.Number, Src.Location, Src.Quantity);

将 Firebird 的 MERGE 用于复杂的 UPSERT:

MERGE INTO Pencils AS Dest
USING (SELECT '12345678/90' AS Number,
              'TOP'         AS Location,
              20            As Quantity
         FROM RDB$DATABASE) Src
   ON (Dest.Number = Src.Number AND Dest.Location = Src.Location)
WHEN MATCHED THEN
   UPDATE SET Dest.Quantity = Dest.Quantity + 10
WHEN NOT MATCHED THEN
   INSERT (Number, Location, Quantity) VALUES (Src.Number, Src.Location, Src.Quantity);

这里唯一的复杂性是您在 UPDATE 时动态计算的 Quantity。如果您只是简单地用静态值覆盖现有记录,则可以更简洁地使用 UPDATE OR INSERT

示例:

SQL> SELECT * FROM Pencils;

NUMBER               QUANTITY LOCATION         
================ ============ ================ 
123                         5 TOP              
123                        10 MID              

SQL> MERGE INTO Pencils AS Dest
CON> USING (SELECT '123' AS Number, 'TOP' AS Location, 20 As Quantity
CON> FROM RDB$DATABASE) Src ON (Dest.Number = Src.Number AND Dest.Location = Src.Location)
CON> WHEN MATCHED THEN
CON>    UPDATE SET Dest.Quantity = Dest.Quantity + 10
CON> WHEN NOT MATCHED THEN
CON>    INSERT (Number, Location, Quantity) VALUES (Src.Number, Src.Location, Src.Quantity);

SQL> SELECT * FROM Pencils;

NUMBER               QUANTITY LOCATION         
================ ============ ================ 
123                        15 TOP              
123                        10 MID              

SQL> SELECT * FROM Pencils;

NUMBER               QUANTITY LOCATION         
================ ============ ================ 
123                         5 TOP              
123                        10 MID              

SQL> MERGE INTO Pencils AS Dest
CON> USING (SELECT '123' AS Number, 'TOP' AS Location, 20 As Quantity
CON> FROM RDB$DATABASE) Src ON (Dest.Number = Src.Number AND Dest.Location = Src.Location)
CON> WHEN MATCHED THEN
CON>    UPDATE SET Dest.Quantity = Dest.Quantity + 10
CON> WHEN NOT MATCHED THEN
CON>    INSERT (Number, Location, Quantity) VALUES (Src.Number, Src.Location, Src.Quantity);

SQL> SELECT * FROM Pencils;

NUMBER               QUANTITY LOCATION         
================ ============ ================ 
123                        15 TOP              
123                        10 MID              
123                        20 BOT       

当然可以使用更新或插入。 但是您将不得不重复您的键值,这会使您的查询变得脆弱(仅更改两个值中的一个 - 并且您的查询行为不当)

UPDATE OR INSERT 
   INTO Pencils(Number, Location, Quantity)
VALUES( '12345678/90', 'TOP', 
  20 + coalesce(
        ( Select Quantity 
             From Pencils 
          where Number = '12345678/90' 
            and Location = 'TOP' )
       ,0 )
       )
MATCHING(Number, Location);

在 Delphi 中,大多数库不支持具有相同名称的多个 SQL 参数,因此您可能必须实际制作两个参数,相似但名称不同,才能使这种方法起作用。

所以,总而言之,MERGE 会是更好、更安全的方法。但为了完整起见,这也应该有效。

select rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version
     , rdb$character_set_name
from rdb$database;
VERSION | RDB$CHARACTER_SET_NAME                                                                                                      
:------ | :---------------------------------------------------------------------------------------------------------------------------
3.0.5   | UTF8                                                                                                                        
create table Pencils( Number varchar(20), Location varchar(10), Quantity int,
   constraint pk_pens primary key (number, location) )
INSERT INTO Pencils(Number, Location, Quantity)
VALUES('12345678/90', 'TOP', 13)

1 行受影响

INSERT INTO Pencils(Number, Location, Quantity)
VALUES('12345678/90', 'MID', 7)

1 行受影响

select * from pencils
NUMBER      | LOCATION | QUANTITY
:---------- | :------- | -------:
12345678/90 | TOP      |       13
12345678/90 | MID      |        7
UPDATE OR INSERT 
   INTO Pencils(Number, Location, Quantity)
VALUES( '12345678/90', 'TOP', 
  20 + coalesce(
          (Select Quantity 
             From Pencils 
          where Number = '12345678/90' 
            and Location = 'TOP')
       ,0 )
       )
MATCHING(Number, Location);

1 行受影响

UPDATE OR INSERT 
   INTO Pencils(Number, Location, Quantity)
VALUES( '12345678/90', 'BOTTOM', 
  20 + coalesce(
          (Select Quantity 
             From Pencils 
          where Number = '12345678/90' 
            and Location = 'BOTTOM')
       ,0 )
       )
MATCHING(Number, Location);

1 行受影响

select * from pencils
NUMBER      | LOCATION | QUANTITY
:---------- | :------- | -------:
12345678/90 | TOP      |       33
12345678/90 | MID      |        7
12345678/90 | BOTTOM   |       20

db<>fiddle here


@pilcrow 问:为了完整起见,您能否显示更新或插入,其中新插入的数量 而不是 只是“零 + 增量”?

基于表达式中的 NULL 语义,只需像这样修改查询的中间部分:

.........
VALUES( '12345678/90', 'TOP', 
  coalesce( 20 + -- increment when found
        ( Select Quantity 
             From Pencils 
          where Number = '12345678/90' 
            and Location = 'TOP' )
       ,  -15 /* new value when not found */ )
       )
.......