2011-01-19 9 views
5

Załóżmy, że masz stolik jak (używam programu SQL Server 2008, nr dziennika kontroli - stół jest ogromny):Wybierz wiersze, gdzie cena nie zmieniły

SecID | Date | Price 
1  1/1/11  10 
1  1/2/11  10 
1  1/3/11  5 
1  1/4/11  10 
1  1/5/11  10 

Załóżmy, że tabela jest ogromny (miliony wierszy dla różne secIDs i data) - Chciałbym wrócić rekordy gdy cena zmienił (patrząc na coś lepszego niż za pomocą kursora i iteracji):

Am próbuje dowiedzieć się, jak dostać:

SecID | StartDate | EndDate | Price 
1  1/1/11  1/2/11 10 
1  1/3/11  1/3/11 5 
1  1/4/11  1/5/11 10 

tj. Inny sposób patrzenia na to jest to, że szukam szeregu dat, w których cena pozostała taka sama.

+0

Jaką bazę danych używasz? – Oded

+0

Czy informacje te są przechowywane w innej tabeli (np. Dzienniku kontroli)? –

+1

Nie jest jasne, co chcesz - czy jest to zestaw rekordów określający zakres dat, dla których cena pozostała taka sama? –

Odpowiedz

8

Jest to "wyspy" problem.

declare @Yourtable table 
(SecID int, Date Date, Price int) 

INSERT INTO @Yourtable 
SELECT 1,GETDATE()-5,10 union all 
SELECT 1,GETDATE()-4,10 union all 
SELECT 1,GETDATE()-3,5 union all 
SELECT 1,GETDATE()-2,10 union all 
SELECT 1,GETDATE()-1, 10 

;WITH cte AS 
(
SELECT SecID,Date,Price, 
     ROW_NUMBER() OVER (PARTITION BY SecID ORDER BY Date) - 
     ROW_NUMBER() OVER (PARTITION BY Price, SecID ORDER BY Date) AS Grp 
FROM @Yourtable 
) 
SELECT SecID,Price, MIN(Date) StartDate, MAX(Date) EndDate 
FROM cte 
GROUP BY SecID, Grp, Price 
ORDER BY SecID, MIN(Date) 
+0

Właściwie ta odpowiedź jest lepsza niż moja :) –

+0

to wygląda dobrze! – Denis

+0

+1 to jest świetne! –

0

myślę, że to powinno działać

SELECT SecID, Min(Date) AS StartDate, Max(Date) AS EndDate, Price FROM BigTable GROUP BY SecID, EndDate Having Min(Date) != MAx(Date) And Date != NULL 
+0

To nie zadziała, ponieważ w wierszu 2 mojego przykładu Min (Data) = Max (Data) i ostatniego wiersza zostaną usunięte (ponieważ w pierwszym wierszu znaleziono już cenę = 10). Dobra próba - myślała o tym przez jakiś czas. (BTW, Data jest oznaczona jako "NOT NULL") – Denis

+0

należy również grupować według ceny, a nie EndDate. W każdym razie, jeśli zastąpisz to i wyjmiesz 'HAVING', to powinno działać dobrze – Lamak

+1

To też nie zadziała, ponieważ jeśli zgrupujesz według SecID, Price, będziesz miał (1, 10) i (1, 5)), więc 2 wiersze tylko w zestawie wyników. Powinieneś ponownie mieć 3: (1, 10), (1, 5) i (1,10). – Denis

2

Jeżeli wartość nie zmienia się, odchylenie std będzie zero

select secId 
    from ... 
group by secId 
having count(*) = 1 
    OR stdev(price) = 0 
+0

+1 To jest sprytne, ciekawe, jak wydajne jest stddev? – Matthew

+0

@Matthew, oprócz konieczności czytania każdego wiersza, nie mogę sobie wyobrazić, że dodaje dużo, ponieważ odczytuje dysk będzie bagno wszystkie operacje w pamięci dzieje. –