Условный столбец в SQL Server, основанный на другом столбце - PullRequest
0 голосов
/ 30 октября 2019

Я ищу решение, чтобы столбец версии в моей таблице основывался на другом столбце.

В моей таблице есть столбец "№ документа". Каждый раз, когда я вставляю новую строку с тем же документом no, я хотел бы увеличить версию столбца.

Я знаю, что могу сделать это с помощью серверной части. Но это означает, что я должен сначала прочитать таблицу, а затем вставить. Моя идея оптимизировать производительность и оставить ее с SQL Server.

Возможно ли это?

pk    DocNo  Version
---------------------
1     ABC     0
2     CBD     0
3     ABC     1
4     FGH     0
5     ABC     2

Ответы [ 4 ]

2 голосов
/ 30 октября 2019

Предполагая, что вы можете параметризовать свой запрос (как в хранимой процедуре), И ваш первичный ключ установлен на IDENTITY, вы можете использовать что-то вроде:

    INSERT INTO TableA (DocNo, Version)
    (SELECT TOP 1 'XYZ',ISNULL(MAX(Version)+1,0) 
      FROM TableA WHERE DocNo = 'XYZ')

Я использовал 'XYZ', где вы бы поместили свой параметр как:

    INSERT INTO TableA (DocNo, Version)
    (SELECT TOP 1 @DocNo,ISNULL(MAX(Version)+1,0) 
      FROM TableA WHERE DocNo = @DocNo)
1 голос
/ 30 октября 2019

Ваш номер версии подразумевается в ваших данных. Используйте PK, чтобы определить его с помощью

SELECT DocNo, ROW_NUMBER() over (PARTITION BY DocNo ORDER BY pk) as version order by DocNo, когда вы извлекаете данные (или помещаете их в представление)

Использование IDENTITY может дать вам пробелы

Полагаться наMAX (x) +1 может не всегда работать в зависимости от вашей модели параллелизма.

Блокировка таблицы / столбца приведет к проблемам параллелизма (которые могут быть неважными или тривиальными в вашем случае).

1 голос
/ 30 октября 2019

Вы можете использовать insert trigger. В триггере обновите Version, получив последние version того же DocNo и увеличив их на 1.

update  t
set     Version = isnull(v.Version, 0) + 1
from    inserted i
        inner join mytable t    on  i.pk = t.pk
        outer apply
        (
            select  Version = max(Version)
            from    mytable x
            where   x.DocNo = i.DocNo
        ) v
1 голос
/ 30 октября 2019

Решение хранимой процедуры

CREATE PROCEDURE tableUpsert(@DocNo varchar(100))
AS
  SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  BEGIN TRAN
    IF EXISTS(SELECT * FROM dbo.YourTable WITH (UPDLOCK) WHERE DocNo = @DocNo)
      UPDATE dbo.YourTable
      SET Version = Version + 1
      WHERE DocNo = @DocNo;
    ELSE
      INSERT dbo.YourTable(DocNo, Version)
      VALUES(@DocNo, 1);
  COMMIT

Код довольно понятен. Если запись существует, вы обновляете ее, увеличивая столбец VersionNumber, а если нет, то вставляете новую запись со значением VersionNumber по умолчанию, равным 1. Обратите внимание на использование UPDLOCK, чтобы гарантировать, что только ваш конкретный процесс в настоящее время обновляет запись.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...