मैंने पुनरावर्ती CTE
का उपयोग करने के बारे में सोचा , लेकिन, जहां तक मुझे पता है, SQL सर्वर में UNION
का उपयोग करना संभव नहीं है एंकर सदस्य और पुनरावर्ती CTE के एक पुनरावर्ती सदस्य को जोड़ने के लिए (मुझे लगता है कि PostgreSQL में करना संभव है), इसलिए डुप्लिकेट को समाप्त करना संभव नहीं है।
declare @i int
with cte as (
select
GroupID,
row_number() over(order by Company) as rn
from Table1
)
update cte set GroupID = rn
select @i = @@rowcount
-- while some rows updated
while @i > 0
begin
update T1 set
GroupID = T2.GroupID
from Table1 as T1
inner join (
select T2.Company, min(T2.GroupID) as GroupID
from Table1 as T2
group by T2.Company
) as T2 on T2.Company = T1.Company
where T1.GroupID > T2.GroupID
select @i = @@rowcount
update T1 set
GroupID = T2.GroupID
from Table1 as T1
inner join (
select T2.Publisher, min(T2.GroupID) as GroupID
from Table1 as T2
group by T2.Publisher
) as T2 on T2.Publisher = T1.Publisher
where T1.GroupID > T2.GroupID
-- will be > 0 if any rows updated
select @i = @i + @@rowcount
end
;with cte as (
select
GroupID,
dense_rank() over(order by GroupID) as rn
from Table1
)
update cte set GroupID = rn
मैंने एक चौड़ाई पहले खोज एल्गोरिदम की भी कोशिश की है। मैंने सोचा कि यह तेज़ हो सकता है (जटिलता के मामले में यह बेहतर है), इसलिए मैं यहां एक समाधान प्रदान करूंगा। मैंने पाया है कि यह SQL दृष्टिकोण से तेज़ नहीं है, हालांकि:
declare @Company nvarchar(2), @Publisher nvarchar(2), @GroupID int
declare @Queue table (
Company nvarchar(2), Publisher nvarchar(2), ID int identity(1, 1),
primary key(Company, Publisher)
)
select @GroupID = 0
while 1 = 1
begin
select top 1 @Company = Company, @Publisher = Publisher
from Table1
where GroupID is null
if @@rowcount = 0 break
select @GroupID = @GroupID + 1
insert into @Queue(Company, Publisher)
select @Company, @Publisher
while 1 = 1
begin
select top 1 @Company = Company, @Publisher = Publisher
from @Queue
order by ID asc
if @@rowcount = 0 break
update Table1 set
GroupID = @GroupID
where Company = @Company and Publisher = @Publisher
delete from @Queue where Company = @Company and Publisher = @Publisher
;with cte as (
select Company, Publisher from Table1 where Company = @Company and GroupID is null
union all
select Company, Publisher from Table1 where Publisher = @Publisher and GroupID is null
)
insert into @Queue(Company, Publisher)
select distinct c.Company, c.Publisher
from cte as c
where not exists (select * from @Queue as q where q.Company = c.Company and q.Publisher = c.Publisher)
end
end
मैंने यह जांचने के लिए अपने संस्करण और गॉर्डन लिनॉफ का परीक्षण किया है कि यह कैसा प्रदर्शन करता है। ऐसा लगता है कि सीटीई बहुत खराब है, मैं 1000 से अधिक पंक्तियों में इसके पूरा होने तक प्रतीक्षा नहीं कर सका।
यह रहा sql fiddle डेमो
यादृच्छिक डेटा के साथ। मेरे परिणाम थे:
128 पंक्तियां :
मेरा आरबीएआर समाधान:190ms
मेरा SQL समाधान:27ms
गॉर्डन लिनॉफ़ का समाधान:958ms
256 पंक्तियां :
मेरा आरबीएआर समाधान:560ms
मेरा SQL समाधान:1226ms
गॉर्डन लिनॉफ़ का समाधान:45371ms
यह यादृच्छिक डेटा है, इसलिए परिणाम बहुत सुसंगत नहीं हो सकते हैं। मुझे लगता है कि इंडेक्स द्वारा समय बदला जा सकता है, लेकिन यह नहीं लगता कि यह पूरी तस्वीर बदल सकता है।
पुराना संस्करण - अस्थायी तालिका का उपयोग करके, केवल प्रारंभिक तालिका को छुए बिना GroupID की गणना करना:
declare @i int
-- creating table to gather all possible GroupID for each row
create table #Temp
(
Company varchar(1), Publisher varchar(1), GroupID varchar(1),
primary key (Company, Publisher, GroupID)
)
-- initializing it with data
insert into #Temp (Company, Publisher, GroupID)
select Company, Publisher, Company
from Table1
select @i = @@rowcount
-- while some rows inserted into #Temp
while @i > 0
begin
-- expand #Temp in both directions
;with cte as (
select
T2.Company, T1.Publisher,
T1.GroupID as GroupID1, T2.GroupID as GroupID2
from #Temp as T1
inner join #Temp as T2 on T2.Company = T1.Company
union
select
T1.Company, T2.Publisher,
T1.GroupID as GroupID1, T2.GroupID as GroupID2
from #Temp as T1
inner join #Temp as T2 on T2.Publisher = T1.Publisher
), cte2 as (
select
Company, Publisher,
case when GroupID1 < GroupID2 then GroupID1 else GroupID2 end as GroupID
from cte
)
insert into #Temp
select Company, Publisher, GroupID
from cte2
-- don't insert duplicates
except
select Company, Publisher, GroupID
from #Temp
-- will be > 0 if any row inserted
select @i = @@rowcount
end
select
Company, Publisher,
dense_rank() over(order by min(GroupID)) as GroupID
from #Temp
group by Company, Publisher