metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2009-07-09 08:34 am

SQL извраты

Не хватает в SQL аггрегирующей операции типа MIN или MAX(поле1, поле2, поле3), т.е. минимум или максимум тупла из полей. Операция сравнения задана обычным образом - сначала сравниваем первое поле, если больше-меньше, то возвращаем результат, если равны - переходим к следующему, итд.
Тогда можно было бы простым образом решать классическую задачу "при группировке выбрать значения некоторых полей в тех записях, где заданное поле имеет минимальное или максимальное значение". Типа например "состояние объекта на начало и конец дня" - группируем по дням и объектам, а аггрегацию делаем в виде MIN(DT,STATUS) и MAX(DT,STATUS).

[identity profile] nolar.livejournal.com 2009-07-09 05:55 am (UTC)(link)
least()? greatest()?
min(least()), max(greatest())?

[identity profile] zamotivator.livejournal.com 2009-07-09 08:40 am (UTC)(link)
select top 1 A, B, C from TABLE order by A,B,C;

[identity profile] gds.livejournal.com 2009-07-09 10:53 am (UTC)(link)
оракловские аналитические функции это умеют, как и многое другое.
нестандарт, разумеется.
склеивать в строку -- тоже вариант, но некоторые значения слишком велики могут быть (строки, например).

[identity profile] ennor.livejournal.com 2009-07-09 05:55 pm (UTC)(link)
"состояние объекта на начало и конец дня", гы-гы (MSSQL 2005, для простоты - на начало и конец смены, т.к. неохота возиться с округлением дат до суток):
declare @log table (
	Id int identity(1,1) primary key,
	ShiftId int not null,
	State1 int not null,
	State2 int null
);

-- Completely random data, just as a sample
insert into @log (ShiftId, State1, State2)
select top 300 low as [ShiftId],
	cast(substring(cast(newid() as binary(16)), 1, 3) as int) as [State1], case
		when (number % 5) % 3 = 0 then null
		else cast(substring(cast(newid() as binary(16)), 1, 3) as int)
	end as [State2]
from master.dbo.spt_values where type = 'P'
order by newid();

-- Now get start and end conditions for each shift
select Id, ShiftId, State1, State2, case RN when 1 then 'Start' else 'End' end as [StateTime]
from (
	select *,
		row_number() over(partition by shiftid order by id) as [rn],
		count(*) over(partition by Shiftid) as [ShiftSize]
	from @log
	) sq
where rn in (1, ShiftSize)
order by ShiftId, rn;

:)))

Если кроме шуток, то возможно почти все, но в каждом случае будет очень сильно зависеть от конкретной СУБД.