количество запущенных серверов sqlserver

#sql-server

#sql-сервер

Вопрос:

Представьте приведенную ниже таблицу в виде

 col1 col2 col3 rank
 1     2   n    5
 1     2   n    6
 2     3   a    3
  

При вставке нижеприведенных записей из таблицы B в таблицу A значение столбца rank должно постоянно увеличиваться, если вставляются одни и те же записи.

Записи в таблице B, которые собираются вставить в A, являются

 col1 col2 col3
 1     2    n
 2     3    a
  

Желаемый результат в таблице A после вставки вышеуказанных записей является,

  col1 col2 col3 rank
   1    2   n    5
   1    2   n    6
   1    2   n    7
   2    3   a    3
   2    3   a    4
  

Пожалуйста, помогите мне, как этого достичь.Спасибо.

Ответ №1:

Если запись в B уникальна, то вы могли бы использовать запрос, подобный этому

—————РЕДАКТИРОВАТЬ——————-

Если в B может быть несколько записей, вы можете использовать функцию row_number() с разделом

 insert into TestA
select b.*, 
(select max([rank]) from TestA where col1 = b.col1 and col2 = b.col2 and col3 = b.col3) 
  row_number()over (partition by col1, col2, col3 order by col1, col2,col3 asc) as N
 from TestB b
  

—————ЗАВЕРШЕНИЕ РЕДАКТИРОВАНИЯ——————-

Примечание: я переименовал таблицу: TestA и TestB

 insert into TestA
select b.*, (select max([rank]) 1 from TestAwhere col1 = b.col1 and col2 = b.col2 and col3 = b.col3)
 from TestB b
  

или с ОБЪЕДИНЕНИЕМ, подобным этому

 insert into testa
select b.*, mr 1 from TestB b
join
(select col1, col2, col3, max([rank]) as mr
from TestA A
group by col1, col2, col3) as M
on 
b.col1 = M.col1 and b.col2 = M.col2 and b.col3 =M.col3
  

Комментарии:

1. Привет, спасибо за твою помощь. Первый код не может работать, поскольку в таблице b отсутствует столбец ran. Я попробовал второй вариант. Проблема с этим заключается в том, что если таблица B имеет повторяющуюся строку, такую же, как и первая строка, то она присваивает тот же ранг и второй записи. Его необходимо увеличить.

2. Я изменил запрос для работы с множественной записью в таблице B

Ответ №2:

Я бы использовал для этого INSTEAD OF INSERT триггер. Вот так:

 CREATE TRIGGER rankInsertTrigger
ON A
INSTEAD OF INSERT
AS
BEGIN
    INSERT INTO A(col1, col2, col3, rank)
    SELECT i.col1, i.col2, i.col3,
           MAX(SELECT a.rank
               FROM A AS a
               WHERE a.col1 = i.col1
                 AND a.col2 = i.col2
                 AND a.col3 = i.col3)   1
    FROM inserted i
END
  

Теперь каждый раз, когда вы вставляете значения в таблицу A , запускается этот триггер и заменяет исходную вставку вставкой, которая задает rank нужное значение.

Например, когда вы это делаете INSERT INTO A(col1, col2, col3) VALUES (1, 2, n) , на самом деле выполняется оператор insert в триггере (который принимает исходные значения для col1 , col2 , col3 но перезаписывает rank ).

Комментарии:

1. не могли бы вы, пожалуйста, объяснить, что это за предложение select в триггере собирается извлечь? Мне будет полезно изменить. Спасибо за вашу помощь.

2. Не похоже, что это будет обрабатывать параллельные вставки.

3. @Robin Внутри триггера ВСТАВКИ есть таблица с именем inserted , которая представляет вставленные записи. Оператор select выбирает данные из inserted таблицы и определяет следующие rank и использует эти данные для вставки в таблицу A .

4. @Martin Правильно, при одновременных вставках вы, скорее всего, получите повторяющиеся rank значения. Единственное исправление заключается в том, чтобы убедиться, что одновременные вставки не выполняются, или в том, что каждая отдельная вставка выполняется внутри сериализуемой транзакции (поскольку вам нужна блокировка чтения для строк, выбранных в MAX запросе). Не уверен, что триггер — лучшее место для включения такой логики.