Funkcja min() i max() + klauzula group by z wyjątkiem

0

Witam, mój uproszczony kod wygląda następująco:

SELECT 
   a.user_id as User_ID,
   min(b.a_day) as Date_from,
   max(b.a_day) as Date_to,
   c.code as ID 
FROM a, b, c 
WHERE 
   a_day > (day, -15, getdate())
GROUP BY 
   a.user_id,
   b.a_day,
   c.code

Zapytanie daje następujący wynik:

User ID date_from date_to id
1234567 2016-06-13 2016-06-13 B
1234567 2016-06-17 2016-06-17 A
1234567 2016-06-18 2016-06-18 A
1234567 2016-06-19 2016-06-19 A
1234567 2016-06-20 2016-06-20 A
1234567 2016-06-21 2016-06-21 B

Przy wyłączeniu z klauzuli GROUP BY kolumny b.a_day, otrzymuję zagregowany wynik w postaci:

User ID date_from date_to id
1234567 2016-06-13 2016-06-21 B
1234567 2016-06-17 2016-06-20 A

Podczas, gdy wynik musiałby wyglądać następująco (chodzi o sumowanie ciągłości dni i osobne wyszczególnienie dni pojedynczych):

User ID date_from date_to id
1234567 2016-06-13 2016-06-13 B
1234567 2016-06-17 2016-06-20 A
1234567 2016-06-21 2016-06-21 B

Dzieliłem się już tym pytaniem na stackoverflow ale nie za bardzo rozumiem odpowiedź:
http://stackoverflow.com/questions/39484658/how-to-group-by-with-an-exception

Z góry dzięki za pomoc.

0

Nie ma takiej mozliwości, przynajmniej nie w przypadku w którym id się powiela, musisz doprowadzić dane do takiej postaći:

User ID date_from date_to id okres
1234567 2016-06-13 2016-06-13 B 1
1234567 2016-06-17 2016-06-17 A 2
1234567 2016-06-18 2016-06-18 A 2
1234567 2016-06-19 2016-06-19 A 2
1234567 2016-06-20 2016-06-20 A 2
1234567 2016-06-21 2016-06-21 B 3

i później grupować dodatkowo po kolumnie okres:

SELECT 
   a.user_id AS User_ID,
   MIN(b.a_day) AS Date_from,
   MAX(b.a_day) AS Date_to,
   c.code AS ID 
FROM a, b, c 
WHERE 
   a_day > (DAY, -15, getdate())
GROUP BY 
   a.user_id,
   c.code,
   okres
0
Panczo napisał(a):

Nie ma takiej mozliwości, przynajmniej nie w przypadku w którym id się powiela, musisz doprowadzić dane do takiej postaći:

User ID date_from date_to id okres
1234567 2016-06-13 2016-06-13 B 1
1234567 2016-06-17 2016-06-17 A 2
1234567 2016-06-18 2016-06-18 A 2
1234567 2016-06-19 2016-06-19 A 2
1234567 2016-06-20 2016-06-20 A 2
1234567 2016-06-21 2016-06-21 B 3

i później grupować dodatkowo po kolumnie okres:

SELECT 
   a.user_id AS User_ID,
   MIN(b.a_day) AS Date_from,
   MAX(b.a_day) AS Date_to,
   c.code AS ID 
FROM a, b, c 
WHERE 
   a_day > (DAY, -15, getdate())
GROUP BY 
   a.user_id,
   c.code,
   okres

Dzięki za odpowiedź. Twoja sugestia wydaje się być prawidłowa. Czy jest opcja zrobienia czegoś na wzór dodatkowej, tymczasowej kolumny, która przechowywałaby takie informacje odpowiadające za dany okres?

0

Oczywiscie, że jest można to zrobić bez niej, cała zabawa polega na wybraniu zakresów tu przydają się funkcje od sql 2012 LAG i LEAD i row_number (jak masz starszą bazę to da się to samo osiągnąć joinami...

Do przetestowania

create table #okresy (
	userid varchar(20)
	,date_from datetime
	,date_to datetime
	,id varchar(1)
)


insert into #okresy values ('1234567','2016-06-13','2016-06-13','B')
insert into #okresy values ('1234567','2016-06-17','2016-06-17','A')
insert into #okresy values ('1234567','2016-06-18','2016-06-18','A')
insert into #okresy values ('1234567','2016-06-19','2016-06-19','A')
insert into #okresy values ('1234567','2016-06-20','2016-06-20','A')
insert into #okresy values ('1234567','2016-06-21','2016-06-21','B')



go
with tmp as (
	select
		row_number() over (partition by userid order by date_from) r
		, LEAD(id,1,'') over (partition by userid order by date_from) l
		,* 
	from 
		#okresy
)
,hlpR as (
	select 
		LAG(r,1,'') over (partition by userid order by r)+1 R_FROM
		,R R_TO 
	from 
		tmp
	where 
		id <> l
)
select 
	userid
	,id
	,min(date_from) date_from
	,max(date_to) date_to
from 
	tmp o
	inner join hlpr on o.r between hlpr.r_from and hlpr.r_to
group by
	userid
	,id
	,r_from
	,r_to
order by
	3
go

drop table #okresy

1 użytkowników online, w tym zalogowanych: 0, gości: 1