4

У меня есть таблицы с данными сотрудника и его коллег, я хочу обновить bucketid в таблице Employee, если есть соответствующие коллеги с другим сотрудником.self join in update query с транзитивными данными

здесь, в этом примере,

Сотрудник = 101 соответствие с Сотрудника = 103 Коллега (т.е. с1), поэтому оба должны иметь тот же bucketid = 1 (т.е. мин обоих bucketids)

и работник = 102 совпадает с Employee = 103 Colleague (т.е. c3), поэтому оба должны иметь одинаковый bucketid, но здесь он должен быть обновлен с 1, поскольку employee = 102 bucketid только что изменился на 1. В этом примере мы имеем данные, зависящие от закона.

(i.e. a=b and b=c then a=c) 

Сотрудник таблице:

EmployeeID EmployeeName BucketID 
101   williams  1 
102   williams  2 
103   williams  3 
104   williams  4 

Employee_Colleague стол:

EmployeeID Colleague 
101   c1 
101   c2 
102   c3 
102   c4 
103   c1 
103   c3 
104   c7 

Я попытался с помощью этого запроса на обновление,

update a2 
set BucketID = a1.BucketID 
from Employee a1 
inner join Emp_Colleagues c1 on a1.EmployeeID=c1.EmployeeID 
inner join Employee a2 on a1.EmployeeName=a2.EmployeeName 
inner join Emp_Colleagues c2 on a2.EmployeeID=c2.EmployeeID 
where c1.Colleague=c2.Colleague and a1.BucketID <> a2.BucketID 

она возвращается ниже выхода.

EmployeeID EmployeeName BucketID 
101   williams  1 
102   williams  1 
103   williams  3 
104   williams  4 

Но я хочу выход, как показано ниже в таблице Employee.

EmployeeID EmployeeName BucketID 
101   williams  1 
102   williams  1 
103   williams  1 
104   williams  4 
+0

В чем проблема с запросом? –

+0

возвращает упомянутый выше вывод, а не тот, который я действительно хотел. – user3789961

+0

Для этого нужен рекурсивный CTE, так как может существовать неопределенное количество переходов, например 'a = b и b = c и c = d', затем' a = d'. –

ответ

1

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

declare @updates int = 1 
while @updates > 0 
begin 
    update a2 
     set BucketID = a1.BucketID 
     from Employee a1 
     inner join Emp_Colleagues c1 on a1.EmployeeID=c1.EmployeeID 
     inner join Emp_Colleagues c2 on c1.Colleague=c2.Colleague 
     inner join Employee a2 on a2.EmployeeID=c2.EmployeeID 
     where a1.BucketID < a2.BucketID 
    set @updates = @@ROWCOUNT 
end 
+0

Я думаю, мы сможем добиться этого, используя рекурсивный CTE .. у вас есть идеи? – user3789961

+0

мы можем сделать это без зацикливания .. рекурсивным CTE .. – user3789961

+0

огромные данные, присутствующие в таблицах выше. Я выполнил этот запрос, но он запускается с 2 дней. – user3789961

0

Вот запрос, который вы ищете.

with CTE as 
(
select EmployeeID as E1, EmployeeID as E2, cast('\' as varchar(MAX)) as list 
from Employee 
Union all 
select E1, T2_2.EmployeeID, CTE.list + CAST(E1 as varchar(MAX)) + '-' + CAST(T2_2.EmployeeID as varchar(MAX)) + '\' 
from CTE 
    inner join Employee_Colleague T2_1 ON CTE.E2 = T2_1.EmployeeID 
    inner join Employee_Colleague T2_2 ON T2_1.Colleague = T2_2.Colleague 
where CTE.list not like '%\' + CAST(E1 as varchar(MAX)) + '-' + CAST(T2_2.EmployeeID as varchar(MAX)) + '\' +'%' 
) 

Update T1_1 
Set T1_1.BucketID = (select MIN(T1_2.BucketID) 
         from Employee T1_2 
          inner join CTE ON T1_1.EmployeeID = CTE.E1 AND T1_2.EmployeeID = CTE.E2 
        ) 
from Employee T1_1