powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сгруппировать по одному из двух параметров
22 сообщений из 22, страница 1 из 1
Сгруппировать по одному из двух параметров
    #40091183
Luna17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте

Подскажите, пожалуйста, можно ли сгруппировать поля по двум колонкам так, чтобы для "попадания" в группу было достаточно совпасть по одной колонке?
Т.е. если у пользователей совпадает LoginName или Year они попадают в одну группу.

Данные для примера:

create table #TestTable
(CustomerID int,
LoginName Varchar(20),
Year Varchar(10))

insert into #TestTable
values ('1', 'Den', '1990'),
('2', 'Sarah', '1990'),
('3', 'Anton', '1977'),
('4', 'James', '1965'),
('5', 'Den', '1994'),
('6', 'Cristian', '1983'),
('7', 'Sarah', '1997'),
('8', 'Mario', '1986'),
('9', 'Mario', '1983')

Желаемый результат:

GroupID___CustomerID___LoginName____Year
___1_________1_________Den_________1990
___1_________2_________Sarah________1990
___1_________5_________Den_________1994
___1_________7_________Sarah_______1997
___2_________6_________Cristian______1983
___2_________8_________Mario_______1986
___2_________9_________Mario_______1983
___3_________3_________Anton_______1977
___4_________4_________James_______1965
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091226
casinozeus
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
хз даже
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091240
Посетитель
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
задача на поиск связных графов
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091260
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
хорошая задача однако :)

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
with
  d as (
    select
         CustomerIDL=t.CustomerID
        ,CustomerIDR=y.CustomerID
        ,P=cast('|'+right('0000000000'+cast(t.CustomerID as varchar), 10)+'|'+right('0000000000'+cast(y.CustomerID as varchar), 10) as varchar(max))
        ,y.LoginName
        ,y.[Year]
      from #TestTable t
      join #TestTable y on t.LoginName=y.LoginName or t.[Year]=y.[Year]
    union all
    select
         CustomerIDL=t.CustomerIDR
        ,CustomerIDR=y.CustomerID
        ,P=t.P+'|'+right('0000000000'+cast(y.CustomerID as varchar), 10)
        ,y.LoginName
		,y.[Year]
	  from d t
      join #TestTable y on (t.LoginName=y.LoginName or t.[Year]=y.[Year]) and t.P not like '%|'+right('0000000000'+cast(y.CustomerID as varchar), 10)+'%'
  )
 ,t as (
    select 
         t.*
        ,P=(select top 1
                 P
              from d 
              where P like '%|'+right('0000000000'+cast(t.CustomerID as varchar), 10)+'%'
              order by datalength(P) desc
                      ,P desc)
      from #TestTable t
  )
  select 
       t.CustomerID
      ,t.LoginName
      ,t.[Year]
      ,GroupId=dense_rank() over (order by datalength(t.P) desc, t.P)
    from t
  
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091292
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Luna17
Здравствуйте

Подскажите, пожалуйста, можно ли сгруппировать поля по двум колонкам так, чтобы для "попадания" в группу было достаточно совпасть по одной колонке?


A 1
А 2
Б 1
Б 3

Это одна группа?

Если да - одним запросом не получится.

Посетитель
задача на поиск связных ПОДграфов
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091294
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
drop table #TestTable

create table #TestTable
(CustomerID int,
LoginName Varchar(20),
Year Varchar(10), GroupID integer)

insert into #TestTable(CustomerID, LoginName, Year)
values ('1', 'Den', '1990'),
('2', 'Sarah', '1990'),
('3', 'Anton', '1977'),
('4', 'James', '1965'),
('5', 'Den', '1994'),
('6', 'Cristian', '1983'),
('7', 'Sarah', '1997'),
('8', 'Mario', '1986'),
('9', 'Mario', '1983')



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
declare @GroupID integer=1;
declare @rc integer;

update t 
set GroupID =@GroupID
from (select top 1 * from #TestTable) t

-- select * from #TestTable

while 1=1 begin
	update t1 
	set t1.GroupID = t2.GroupID
	from #TestTable t1 inner join #TestTable t2 on t1.LoginName=t2.LoginName
	where t2.GroupID is not null and t1.GroupID is null;

	set @rc = @@rowcount;

	update t1 
	set t1.GroupID = t2.GroupID
	from #TestTable t1 inner join #TestTable t2 on t1.Year=t2.Year
	where t2.GroupID is not null and t1.GroupID is null;

	set @rc = @rc + @@rowcount;

	if @rc = 0 begin
		set @GroupID = @GroupID + 1;

		update t 
		set GroupID =@GroupID
		from (select top 1 * from #TestTable where GroupID is null) t	
		
		if @@rowcount = 0 break;
	end
end 

select * from #TestTable order by 4,1
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091300
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
court

Код: sql
1.
2.
3.
4.
5.
6.
declare @GroupID integer=1;
declare @rc integer;

update t 
set GroupID =@GroupID
from (select top 1 * from #TestTable) t



Плохо.
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091304
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,

оцените тогда и мое решение. или покажете сразу как хорошо? :)
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091307
Фотография court
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222
court

Код: sql
1.
2.
3.
4.
5.
6.
declare @GroupID integer=1;
declare @rc integer;

update t 
set GroupID =@GroupID
from (select top 1 * from #TestTable) t




Плохо.
нуу, улучшение я вижу только одно - при инициализации GroupID = 1, "пометить" сразу полностью по одному, одинаковому у макс.кол-ва записей признаку
(типа всех LoginName=Den отметить)
... но сильно уж это "замороченно" показалось )

или что-то ещё имеешь в виду ?
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091351
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Luna17,

Den 1983 - это какая группа 1 или 2?

задача на поиск связных графов
ага
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091382
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
court
aleks222
пропущено...


Плохо.
нуу, улучшение я вижу только одно - при инициализации GroupID = 1, "пометить" сразу полностью по одному, одинаковому у макс.кол-ва записей признаку
(типа всех LoginName=Den отметить)
... но сильно уж это "замороченно" показалось )

или что-то ещё имеешь в виду ?


Надо сразу все группы обрабатывать, а не по-одной.

Надо выдавливать из себя императивного программизда.
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091388
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
declare @GroupID int = 0;
declare @rc int = 1;

update t set GroupID = @GroupID, @GroupID = @GroupID + 1 from #TestTable t;

select * from #TestTable;

while @rc > 0 begin

	update t1 set GroupID = t2.GroupID
	  from #TestTable t1 inner join #TestTable t2 on t1.LoginName = t2.LoginName and t2.GroupID < t1.GroupID
	;
	set @rc = @@rowcount;

	update t1 set GroupID = t2.GroupID
	  from #TestTable t1 inner join #TestTable t2 on t1.Year = t2.Year and t2.GroupID < t1.GroupID
    ;
	set @rc = @rc + @@rowcount;

end;

select * from #TestTable order by 4,1
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091438
Luna17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,
A 1
А 2
Б 1
Б 3
да, это одна группа
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091439
Luna17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Владислав Колосов
Luna17,

Den 1983 - это какая группа 1 или 2?

задача на поиск связных графов

ага

Если бы появился Den 1983 первая и вторая группа объеденились бы под айди 1
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091502
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Luna17
aleks222,
A 1
А 2
Б 1
Б 3
да, это одна группа


Изучайте наши тезисы

aleks222
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
declare @GroupID int = 0;
declare @rc int = 1;

update t set GroupID = @GroupID, @GroupID = @GroupID + 1 from #TestTable t;

select * from #TestTable;

while @rc > 0 begin

	update t1 set GroupID = t2.GroupID
	  from #TestTable t1 inner join #TestTable t2 on t1.LoginName = t2.LoginName and t2.GroupID < t1.GroupID
	;
	set @rc = @@rowcount;

	update t1 set GroupID = t2.GroupID
	  from #TestTable t1 inner join #TestTable t2 on t1.Year = t2.Year and t2.GroupID < t1.GroupID
    ;
	set @rc = @rc + @@rowcount;

end;

select * from #TestTable order by 4,1



Чуток их, канешно, можно оптимизировать. Но суть та.
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091515
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Luna17,


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

DROP TABLE IF EXISTS #TestTable;
GO

CREATE TABLE #TestTable(
             CustomerID INT, 
             LoginName  VARCHAR(20), 
             Year       VARCHAR(10));

INSERT INTO #TestTable
     VALUES ('1', 'Den', '1990'), 
            ('2', 'Sarah', '1990'), 
            ('3', 'Anton', '1977'), 
            ('4', 'James', '1965'), 
            ('5', 'Den', '1994'), 
            ('6', 'Cristian', '1983'), 
            ('7', 'Sarah', '1997'), 
            ('8', 'Mario', '1986'), 
            ('9', 'Mario', '1983')
        --,('10', 'Den', '1983') -- для проверки ))

;WITH cte 
    AS (SELECT a.CustomerID, 
               a.LoginName, 
               a.Year, 
               MIN(b.Year) AS x
          FROM #TestTable AS a
               CROSS JOIN #TestTable AS b
         WHERE a.LoginName = b.LoginName OR a.Year = b.Year
         GROUP BY a.CustomerID, 
                  a.LoginName, 
                  a.Year),
    orderedgroup -- Только для того, чтобы номер группы был именно в том порядке как в задании
    AS (SELECT CustomerID, 
               LoginName, 
               Year, 
               MIN(CustomerID) OVER(PARTITION BY x) gr
          FROM cte)

SELECT CustomerID, 
       LoginName, 
       Year, 
       DENSE_RANK() OVER(ORDER BY gr) gr
FROM orderedgroup
ORDER BY gr, CustomerID
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091522
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Oleg_SQL,
впечатлило
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091542
Посетитель
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spenov,

а зря.

увеличь длину цепочки и посмотри результат
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091544
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Посетитель,
мне понравилось. на конкретно приведенных данных работает же.

если добавить например строку ('10', 'James', '1997'), то сломается :)
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091546
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
spenov
Посетитель,
мне понравилось. на конкретно приведенных данных работает же.

если добавить например строку ('10', 'James', '1997'), то сломается :)


да, не учел такое. вот с поправкой (группы не упорядочивал)

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;

DROP TABLE IF EXISTS #TestTable;
GO

CREATE TABLE #TestTable(
             CustomerID INT, 
             LoginName  VARCHAR(20), 
             Year       VARCHAR(10)
);

INSERT INTO #TestTable
     VALUES ('1', 'Den', '1990'), 
            ('2', 'Sarah', '1990'), 
            ('3', 'Anton', '1977'), 
            ('4', 'James', '1965'), 
            ('5', 'Den', '1994'), 
            ('6', 'Cristian', '1983'), 
            ('7', 'Sarah', '1997'), 
            ('8', 'Mario', '1986'), 
            ('9', 'Mario', '1983')
            ,('10', 'Den', '1983') -- для проверки ))

;WITH cte
     AS (SELECT a.CustomerID, 
                a.LoginName, 
                a.Year, 
                MIN(b.Year) AS mn, 
                MAX(b.Year) AS mx
           FROM #TestTable AS a
                CROSS JOIN #TestTable AS b
          WHERE a.LoginName = b.LoginName
                OR a.Year = b.Year
          GROUP BY a.CustomerID, 
                   a.LoginName, 
                   a.Year),
    grp AS (
     SELECT CustomerID, 
            LoginName, 
            Year,
            CASE
                WHEN LAG(mx) OVER(ORDER BY year, mn, CustomerID) BETWEEN mn AND mx
                     OR LAG(mn) OVER(ORDER BY year, mn, CustomerID) BETWEEN mn AND mx 
                THEN IIF(LAG(mn) OVER(ORDER BY year, mn, CustomerID) < mn, LAG(mn) OVER(ORDER BY year, mn, CustomerID), mn)
                ELSE mn
            END AS gr
       FROM cte
       )

       SELECT CustomerID, 
              LoginName, 
              Year,
              DENSE_RANK() OVER(ORDER BY gr) grp
         FROM grp
         ORDER BY grp, CustomerID
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091549
spenov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Oleg_SQL,
а если цепочка будет длиннее? если я правильно понял, у вас обрабатывается первый и второй шаг. а шагов может быть произвольное количество. мое решение очень похоже на ваше, но я накапливаю узлы в строке. а у вас вроде как нет накопления информации о пройденных узлах.
...
Рейтинг: 0 / 0
Сгруппировать по одному из двух параметров
    #40091551
Oleg_SQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
spenov,

да, не в ту сторону завернуло ))
...
Рейтинг: 0 / 0
22 сообщений из 22, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Сгруппировать по одному из двух параметров
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]