SQL Server Как вставить, когда не существует? - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть две таблицы, одна называется Счет-фактура, а другая - Записи.

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

Ответы [ 4 ]

0 голосов
/ 19 декабря 2018

Я сделаю это так:

    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
0 голосов
/ 19 декабря 2018

Вам нужно LEFT JOIN

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;

Значение 1 - это StartNum, а 14 - это MAX MaxNum.Я использовал VALUES, потому что число известно, вы можете использовать RecursiveCTE, чтобы сгенерировать недостающий InvoiceNum, затем СЛЕДУТЬ ПОДКЛЮЧИТЬ CTE к вашей таблице.

Демо

0 голосов
/ 19 декабря 2018

@ Андрей Николов рассказал, но я работал над этим последние 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;
0 голосов
/ 19 декабря 2018

Вам необходимо сгенерировать таблицу с числами, чтобы охватить необходимый диапазон чисел (для каждой строки в таблице Records, от StartNum до MaxNum).Например, вы можете сделать это, выбрав одну из существующих таблиц с достаточным количеством строк и используя оконную функцию 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)
...