【问题标题】:SQL Server How to insert when not exist?SQL Server 不存在时如何插入?
【发布时间】:2018-12-19 16:34:08
【问题描述】:

我有两张表,一张叫 Invoices,另一张叫 Records。

CREATE TABLE Invoices
(
    InvoiceNum INT NOT NULL,
    Amount DECIMAL,
    RecordPK UNIQUEIDENTIFIER NOT NULL
)

CREATE TABLE Records(
    RecordPK UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
    StartNum INT NOT NULL,
    NextNum INT NOT NULL,
    MaxNum INT NOT NULL,
    InvPrefix VARCHAR(2) NOT NULL
)

记录表将记录发票起始编号、我们创建了多少个发票(NextNum)以及我们可以创建多少个发票(MaxNum)。

例如,假设我们在两个表中有几条记录。

发票表:

InvoiceNum    Amount    RecordPk
1             19.00     EDFA0541-5583-4CDD-BDFF-21D6F6504522
2             50.00     EDFA0541-5583-4CDD-BDFF-21D6F6504522
3             3.00      EDFA0541-5583-4CDD-BDFF-21D6F6504522
10            1.00      D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9
11            99.00     D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9
12            13.00     D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9

记录表:

RecordPk                                StartNum    NextNum    MaxNum    Prefix
EDFA0541-5583-4CDD-BDFF-21D6F6504522    1           4          10        AA
D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9    10          13         14        AA

我的问题是,当我搜索带有前缀 AA 的发票表时,我怎样才能得到如下结果,InvoiceNum 应该达到 MaxNum,不存在行的 Amount 和 RecordPK 应该留空,Remark 列应该填写空白。

InvoiceNum    Amount    RecordPk                                Remark
1             19.00     EDFA0541-5583-4CDD-BDFF-21D6F6504522
2             50.00     EDFA0541-5583-4CDD-BDFF-21D6F6504522
3             3.00      EDFA0541-5583-4CDD-BDFF-21D6F6504522
4                                                               Blank
5                                                               Blank
6                                                               Blank
7                                                               Blank
8                                                               Blank
9                                                               Blank
10            1.00      D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9
11            99.00     D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9
12            13.00     D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9
13                                                              Blank
14                                                              Blank

【问题讨论】:

    标签: sql sql-server insert sql-server-2016


    【解决方案1】:

    您需要生成一个包含数字的表格,以涵盖您需要的数字范围(对于Records 表格中的每一行,从StartNumMaxNum)。例如,您可以通过从具有足够行数的现有表中选择并使用ROW_NUMBER 窗口函数来执行此操作。然后过滤此序列以仅包含您需要的数字。左加入Invoices表显示对应发票的数据,并使用IIF函数查看是否有该编号的发票。

    declare @Invoices table(InvoiceNum INT NOT NULL, Amount DECIMAL, RecordPK UNIQUEIDENTIFIER NOT NULL)
    declare @Records table(RecordPK UNIQUEIDENTIFIER NOT NULL PRIMARY KEY, StartNum INT NOT NULL, NextNum INT NOT NULL, MaxNum INT NOT NULL, InvPrefix VARCHAR(2) NOT NULL)
    
    insert into @Invoices(InvoiceNum, Amount, RecordPk) values
    (1 ,            19.00,    'EDFA0541-5583-4CDD-BDFF-21D6F6504522'),
    (2 ,            50.00,    'EDFA0541-5583-4CDD-BDFF-21D6F6504522'),
    (3 ,            3.00 ,    'EDFA0541-5583-4CDD-BDFF-21D6F6504522'),
    (10,            1.00 ,    'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9'),
    (11,            99.00,    'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9'),
    (12,            13.00,    'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9')
    
    insert into @Records(RecordPk, StartNum, NextNum, MaxNum, InvPrefix) values
    ('EDFA0541-5583-4CDD-BDFF-21D6F6504522',    1 ,          4 ,         10,        'AA'),
    ('D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9',    10,          13,         14,        'AA')
    
    ;with numbers as (select ROW_NUMBER() over(order by object_id) as No from sys.objects)
    select
        n.No as InvoiceNum
        , inv.Amount
        , inv.RecordPK
        , IIF(inv.InvoiceNum is null, 'Blank', null) as Remark
    from numbers n
    left join @Invoices inv on n.No = inv.InvoiceNum
    where exists(select * from @Records r where r.StartNum <= n.No and n.No <= r.MaxNum)
    

    【讨论】:

      【解决方案2】:

      @Andrey Nikolov 已经涵盖了它,但是我在过去的 15 分钟里一直在研究这个,所以我想我还是会发布它。

      基本上应该使用中间表来计算您没有的值,然后在我的这个答案版本中,我使用联合查询来生成“空白”值。为简洁起见,我没有包含唯一标识符,但应用程序是相同的。

      if OBJECT_ID('tempdb..#invoice') is not null drop table #invoice;
      if OBJECT_ID('tempdb..#rowcount') is not null drop table #rowcount;
      
      create table #invoice
          (
              invoicenum int,
              amount decimal
          );
      
      
      insert into #invoice (invoicenum, amount)
      values
      (1, 19.00),
      (2, 50.00),
      (3, 3.00),
      (10, 1.00),
      (11, 99.00),
      (12, 13.00);
      
      
      create table #rowcount
      
          (
              rownumber int 
          );
      
      declare @max int = 1;
      
      select @max=count(*) from #invoice;
      
      declare @runs int = 1;
      
      while @runs<=@max
      begin
      insert into #rowcount (rownumber)
      values (@runs);
      select @runs=@runs+1;
      end
      
      
      select invoicenum, cast(amount as nvarchar(25)) as amount from #invoice
      union
      select rownumber, 'BLANK' from #rowcount r left join #invoice i on 
      r.rownumber=i.invoicenum where i.invoicenum is null
      order by invoicenum;
      
      drop table #invoice, #rowcount;
      

      【讨论】:

        【解决方案3】:

        你需要一个左连接

        SELECT I.*,
               CASE WHEN I.InvoiceNum IS NULL THEN 'Blank' END Remark
        FROM (VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14)) RC (InvoiceNum)
        LEFT JOIN Invoices I
             ON RC.InvoiceNum = I.InvoiceNum;
        

        1StartNum14 是最大值MaxNum。 我使用 VALUES 是因为数字是已知的,您可以使用 RecursiveCTE 生成缺少的InvoiceNum,然后将 CTE 与您的表连接起来。

        Demo

        【讨论】:

        • 谢谢 Sami,实际上,invoice 表中的行可以是数千行。
        【解决方案4】:

        我会这样做:

            IF OBJECT_ID('tempdb..#Invoices') IS NOT NULL DROP TABLE #Invoices
        
            CREATE TABLE #Invoices
            (
                InvoiceNum INT NOT NULL,
                Amount DECIMAL,
                RecordPK UNIQUEIDENTIFIER NOT NULL
            )
        
            IF OBJECT_ID('tempdb..#Records') IS NOT NULL DROP TABLE #Records
        
            CREATE TABLE #Records(
                RecordPK UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
                StartNum INT NOT NULL,
                NextNum INT NOT NULL,
                MaxNum INT NOT NULL,
                InvPrefix VARCHAR(2) NOT NULL
            )
        
            INSERT INTO #Invoices
            SELECT 1, 19.00, 'EDFA0541-5583-4CDD-BDFF-21D6F6504522'
            UNION SELECT 2 , 50.00, 'EDFA0541-5583-4CDD-BDFF-21D6F6504522'
            UNION SELECT 3 , 3.00 , 'EDFA0541-5583-4CDD-BDFF-21D6F6504522'
            UNION SELECT 10 , 1.00 , 'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9'
            UNION SELECT 11 , 99.00, 'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9'
            UNION SELECT 12 , 13.00, 'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9'
        
            INSERT INTO #Records
            SELECT 'EDFA0541-5583-4CDD-BDFF-21D6F6504522', 1, 4, 10, 'AA'
            UNION SELECT 'D64EFF0E-65D5-467E-8C82-BFBB6A24AAC9', 10, 13, 14, 'AA'
        
            DECLARE @MAX_NUM INT = (SELECT MAX(MaxNum) FROM #Records)
            DECLARE @TEMP_INV TABLE (InvoiceNum INT)
            INSERT INTO @TEMP_INV
            SELECT Num
            FROM
            (
                SELECT ROW_NUMBER() OVER(ORDER BY object_id) AS Num FROM sys.objects
            ) A
            WHERE Num <= @MAX_NUM
        
            IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL DROP TABLE #TEMP
        
            SELECT I.InvoiceNum, I.Amount, I.RecordPK
            INTO #TEMP
            FROM #Invoices I
            INNER JOIN #Records R
                ON I.RecordPK = R.RecordPK
            WHERE R.InvPrefix = 'AA'
        
            SELECT A.InvoiceNum, B.Amount, B.RecordPK, CASE WHEN B.InvoiceNum IS NULL THEN 'BLANK' END AS Remark
            FROM @TEMP_INV A
            LEFT JOIN #TEMP B
                ON A.InvoiceNum = B.InvoiceNum
        

        【讨论】:

          猜你喜欢
          • 2014-01-25
          • 2011-09-01
          • 1970-01-01
          • 2018-09-30
          • 2018-10-08
          • 1970-01-01
          • 2011-02-05
          • 2019-01-24
          相关资源
          最近更新 更多