Sqlserver
 sql >> डेटाबेस >  >> RDS >> Sqlserver

कई से कई संबंधों में सभी संबंधित रिकॉर्ड समूहित करें, SQL ग्राफ़ कनेक्टेड घटक

मैंने पुनरावर्ती 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 fiddle डेमो

मैंने एक चौड़ाई पहले खोज एल्गोरिदम की भी कोशिश की है। मैंने सोचा कि यह तेज़ हो सकता है (जटिलता के मामले में यह बेहतर है), इसलिए मैं यहां एक समाधान प्रदान करूंगा। मैंने पाया है कि यह 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

sql fiddle डेमो

मैंने यह जांचने के लिए अपने संस्करण और गॉर्डन लिनॉफ का परीक्षण किया है कि यह कैसा प्रदर्शन करता है। ऐसा लगता है कि सीटीई बहुत खराब है, मैं 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

=> sql fiddle उदाहरण



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL सर्वर 2008 के लिए sp_generate_inserts

  2. न्यूल के बजाय मैं चयन कथन एसक्यूएल के परिणामस्वरूप `0` कैसे दिखा सकता हूं?

  3. SQL समूह दिन के अनुसार, प्रत्येक दिन के लिए आदेश दिखाएं

  4. SQL सर्वर (T-SQL) में वर्तमान सत्र की भाषा प्राप्त करने के 3 तरीके

  5. SPSS से क्वेरी SQL सर्वर कैसे कनेक्ट करें