Обновить несколько таблиц несколькими строками с помощью триггера

#sql-server #triggers #common-table-expression

#sql-сервер #триггеры #common-table-expression

Вопрос:

У меня есть эти таблицы Users, UserPackages, Packages, Refers .

Users в таблице есть столбцы UserRef_NO (его собственный уникальный номер), RefNo (если он зарегистрировался, используя чей-то ссылочный номер) и Refarning (где он / она получает доход, если кто-то зарегистрировался, используя его RefNo и купил пакет, и статус пакета изменился на ‘True’).

UserPackages таблица содержит столбцы U_ID (внешний ключ к Users ), P_ID (внешний ключ к Packages ), PackageStatus (true, если приобретено значение false, если нет), BuyDate (генерируется, как только PackageStatus изменяется на true), ExpiryDate (вычисляется из объединения Packages таблицы и BuyDate где срок действия равен общему количеству дней Packages )

Packages в таблице есть столбцы Price , ReferComission (в процентах), Validity (в днях).

РЕДАКТИРОВАТЬ: — Третье редактирование это отлично работает для однорядных обновлений, но не работает для многорядных обновлений, в которых говорится, что подзапрос вернул более одного значения

 alter TRIGGER [dbo].[HeavyTriggerTest] ON [dbo].[UserPackages]
   after update
   as

  update UP set
  BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate()) 
from dbo.UserPackages UP
inner join Inserted I on I.P_ID = UP.P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';

  ;
 with firstCte(Name,UID,PName,Price,ReferComission,ReferredBy)
 as
 (
 select distinct Users.Name,Users.ID,Packages.PName,Packages.Price,Packages.ReferCommission,(select DISTINCT ID from Users
 where Users.UserRef_No=Refers.RefOf )
 from Users inner join UserPackages on UserPackages.U_ID=Users.ID
  inner join Packages on Packages.PID=UserPackages.P_ID
  inner join Refers on Users.Ref_No=Refers.RefOf  
  inner join Inserted I on I.U_ID = UserPackages.U_ID and I.P_ID = UserPackages.P_ID
 and UserPackages.PackageStatus='true' AND UserPackages.U_ID=i.U_ID 
 AND Refers.RefOf=(SELECT users.Ref_No where UserPackages. U_ID=i.U_ID)
 )

 update  Users set RefEarning = Price*ReferComission/100 from firstCte where ID=ReferredBy ;
    

 update Users set Active='True' where ID=(select U_ID from inserted) and Active='False'
  

и вот один запрос на обновление, который я пытался заменить на предыдущие два обновления, но он дает неправильные результаты, плюс он также не работает для обновлений нескольких строк

  update Users set RefEarning =(
 case when ID=firstCte.ReferredBy then firstCte.Price*ReferComission/100 else RefEarning end)
 ,Active=case when ID=(select U_ID from inserted) and Active='false'  then 'True' 
 when firstCte.ReferredBy=(select U_ID from inserted) then 'true' else Active end
  from  firstCte
  

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

1. Просто присоединитесь Inserted к вашему запросу. Или используйте в качестве вашего предыдущего вопроса.

2. Люди уже потратили много времени, пытаясь объяснить вам, как это работает. Inserted — это, по сути, таблица, используйте ее так же, как и любую другую таблицу. И Google вставил таблицу sql server и узнал немного больше. Если вы будете продолжать заставлять людей писать этот код для вас, вы не узнаете, как все это работает.

3. @DaleK я думаю, что я понял концепцию вставленной таблицы, приведенный выше запрос, который я опубликовал, не первый. я создал много других, но только приведенный выше работает нормально для одной обновленной строки, все остальные работают не для всех таблиц, т. Е. несколько таблиц обновлены, несколько нет. Объединение со вставленной таблицей не сработало в приведенном выше случае … самый первый запрос на обновление работает нормально, т. Е. Он изменяет статус пакета в таблице пользовательских пакетов, но больше ничего не обновляется

4. Я только что рассказал вам о 2 методах, которые можно использовать, чтобы сделать его многострочным, либо присоединиться к нему, либо использовать его как IN в соответствии с вашим предыдущим вопросом. Так что попробуйте это и дайте нам знать, когда вы застряли.

Ответ №1:

Ваш второй запрос, первое обновление, вам нужно объединить Inserted в качестве:

 update UP set
  BuyDate = GETDATE(), Expirydate = dateadd(dd, P.Validitiy, getdate()) 
from dbo.UserPackages UP
inner join Inserted I on I.P_IP = UP_P_ID and I.U_ID = UP.U_ID
inner join dbo.Packages P on P.PID = I.P_ID
where UP.PackageStatus = 'True';
  

Обратите внимание на псевдонимы таблиц, которые я рекомендовал вам в вашем последнем вопросе — они значительно облегчают чтение запроса.

Также обратите внимание на то, что рекомендуется использовать схему для квалификации ваших таблиц.

Второй запрос, второе обновление:

 with firstCte ([Name], [UID], PName, Price, ReferComission, ReferredBy)
as
(
  select U.[Name], U.ID, P.PName, P.Price, P.ReferCommission
    , max(U.ID) over () as referedby 
  from Users U
  inner join UserPackages UP on UP.U_ID = U.ID
  inner join Packages P on P.PID = UP.P_ID
  inner join Refers R on R.RefOf = U.Ref_No 
  inner join Inserted I on I.U_ID = UP.U_ID and I.P_ID = UP.P_ID
  where UP.PackageStatus='true' 
)
update U set
  Active = 'True'
  , RefEarning  = Price*ReferComission/100
from Users U
inner join firstCte on ReferredBy = U.id
where Active = 'False';
  

Обратите внимание на функцию window max , чтобы избежать повторения запроса в подзапросе.

Обратите внимание на присоединение CTE к таблице Users для выполнения обновления.

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

1. обновляется то же самое, только первая строка .. это dbo обновления запроса на тестовое обновление. Пользовательские пакеты УСТАНАВЛИВАЮТ PackageStatus = ‘True’, ГДЕ U_ID В (9,2) и P_ID в (1,3);

2. @Jazz тогда ваша фактическая логика (которую я только что скопировал), должно быть, неверна. Здесь показано, как выполнить правильное многорядное обновление, но вы должны убедиться, что ваши объединения, логика и т.д. Работают правильно, поскольку у нас недостаточно информации для этого.

3. Вы можете имитировать триггер, создав временную таблицу #Inserted и поместив в нее несколько строк, а затем протестировать данные, возвращаемые вашими запросами. Или в качестве первого шага вы можете добавить целую загрузку инструкций select в свой триггер и вызвать обновление из SSMS. Теперь это задание отладки, вы должны исследовать и определить, в какой момент оно не дает вам ожидаемых результатов.

4. приведенный выше запрос, который вы опубликовали, а также тот, который я опубликовал, отлично работает при обновлении любой отдельной строки, но не выполняется для запроса обновления, который я опубликовал выше в комментариях

5. Как я уже сказал, что-то не так с логикой… вам нужно отладить его.