Chcę znaleźć sposób na wykrywanie bliższych relacji pomiędzy ludźmi z różnych środowisk opierając się na tabeli: "A zna B" etc. Zaczynam od wyszukania osób skupiających największą liczbę innych, na podstawie powiązań. Dalej przyporządkowuję im tych, którzy mają z nimi jakiś związek tworząc grupę o nazwie tego, kto jest jej centrum. Z tych danych chcę wyciągnąć tylko tych powiązanych z centrum, którzy mają również powiązanie z innymi w swojej grupie. Kolejnym krokiem będzie rozszerzenie grupy na znajomych znajomych, a raczej na grupy, do których należą znajomi z aktualnie przeglądanej. Napisałem funkcję, ale spotkałem się z błędem w warunku if'a trzeciego, najbardziej zagnieżdżonego kursora cr_pairs.
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Nie ma problemów z czytaniem, więcej z doświadczeniem. Oprócz pytania o to, jak najlepiej poprawić ten warunek będę wdzięczny za ogólną opinię nt. podejścia do sprawy. Poniżej przykładowe dane testowe w skróconej objętościowo wersji:
drop table irelations
GO
create table irelations
(
relID int identity(1, 1) primary key,
p1 varchar(1) not null,
p2 varchar(1) not null
);
GO
insert into irelations values ('A', 'B');
insert into irelations values ('B', 'C');
insert into irelations values ('C', 'D');
insert into irelations values ('C', 'M');
insert into irelations values ('D', 'E');
insert into irelations values ('D', 'M');
insert into irelations values ('E', 'G');
insert into irelations values ('E', 'F');
insert into irelations values ('F', 'G');
insert into irelations values ('F', 'Z');
insert into irelations values ('G', 'L');
insert into irelations values ('G', 'H');
insert into irelations values ('H', 'L');
insert into irelations values ('H', 'I');
insert into irelations values ('I', 'L');
insert into irelations values ('I', 'K');
insert into irelations values ('I', 'J');
insert into irelations values ('J', 'K');
i oczywiście sama funkcja:
create function sn (@tableName varchar)
returns @resultTable table (groupName varchar(1), groupMember varchar(1))
as
begin
declare @t1Table table (groupCenter varchar(1), groupMembers varchar(1))
insert into @t1Table
select group_centers.Os as Grupa, friends.p1 as Znajomi
from
(
select connections.Osoba as "Os", connections.CN as PDegree
from
(
select p1 as Osoba, SUM(ile) as CN
from
(
select p1, COUNT(*) as ile from irelations group by p1
union all
select p2, COUNT(*) as ile from irelations group by p2
) as ilosc_relacji
group by ilosc_relacji.p1
) as connections
where connections.CN >= 4
) as group_centers
join
(
select tt.p1 from
(
select p1 from irelations
union
select p2 from irelations
) as tt
) as friends
on ((((cast(group_centers.Os as varchar)+cast(friends.p1 as varchar)) in (select cast(p1 as varchar)+cast(p2 as varchar) from irelations))))
or (((cast(friends.p1 as varchar))+(cast(group_centers.Os as varchar)) in (select cast(p1 as varchar)+cast(p2 as varchar) from irelations)))
declare cr_sieve1 cursor for
select groupCenter, groupMembers from @t1Table
declare @gcenter varchar(1) -- group center: PreviousGroupName
declare @gmember varchar(1) -- group member inside cursor
declare @pgn varchar(1) = '#' -- PreviousGroupName
declare @tt table (m varchar(1)) -- TempTable of m-embers
open cr_sieve1
fetch next from cr_sieve1 into @gcenter, @gmember -- pobierz nazwe potencjalnej grupy
set @pgn = @gcenter -- NazwaPoprzedniejGrupy
insert into @tt select @gmember -- add group member to the table
while @@FETCH_STATUS = 0 -- do konca tabeli
begin
-- set @ttn = @gcenter -- group center is a name of temp table
fetch next from cr_sieve1 into @gcenter, @gmember
if @gcenter <> @pgn
begin
declare cr_mi cursor for select m from @tt
declare @member varchar(1)
declare @tempPairs table (tp1 varchar(1), tp2 varchar(1)) -- tabela par punktow grupy
insert into @tempPairs -- wpisanie unikalnych par punktow danej grupy
select t1.m as m1, t2.m as m2 from @tt as t1, @tt as t2
where t1.m < t2.m
order by t1.m
open cr_mi
fetch next from cr_mi into @member
while @@FETCH_STATUS = 0
begin -- dla kazdego punktu z tabeli znajomych grupy wchodzimy do tabeli unikalnych par znajomych tej grupy
declare cr_pairs cursor for select tp1, tp2 from @tempPairs
declare @p1 varchar(1), @p2 varchar(1)
open cr_pairs
fetch next from cr_pairs into @p1, @p2
if
( (@member = @p1) or (@member = @p2) -- jezeli aktualny znajomy jest w parze
and
( -- ktora zawarla ze soba znajomosc
( CAST(@p1 as varchar)+CAST(@p2 as varchar) in (select * from irelations))
or ( CAST(@p2 as varchar)+CAST(@p1 as varchar) in (select * from irelations))
) )
begin
insert into @resultTable select @gcenter, @p1
insert into @resultTable select @gcenter, @p2
end
close cr_pairs
deallocate cr_pairs
end
close cr_mi
deallocate cr_mi
set @pgn = @gcenter
end
else
insert into @tt select @gmember
end
close cr_sieve1
deallocate cr_sieve1
return
end;