2012-02-16 9 views
7

Se ho la seguente tabelladisaggregare tavolo su 2 colonne in T-SQL

Hour Clicks Conversions 
12:00 2 0 
1:00 3 2 
2:00 1 1 

Come faccio a scrivere uno statment SELECT che dissaggrates trasversalmente entrambe le colonne, in modo da ottenere:

12:00 1 0 
12:00 1 0 
1:00 1 0 
1:00 1 1 
1:00 1 1 
2:00 1 1 

Se non riesco a farlo con un SELECT, come faccio a scrivere un proc memorizzato che lo fa con un ciclo?

Grazie!

+0

Creare un CLR sp –

+0

+1 problema interessante. Non uno nuovo, ma mi ci sono voluti alcuni minuti per pensare alla soluzione, quindi hai ricevuto un voto da parte mia. :-) –

+0

Non vedo il punto della seconda colonna che sembra sempre restituire 1 –

risposta

5

Questo presuppone che ci sarà sempre una sola riga per qualsiasi valore dato di [Hour]. Se possono esserci duplicati, vorrei prima aggregarli (presumo che la fonte sia già un'aggregazione di qualche tipo).

DECLARE @x TABLE ([Hour] CHAR(5), Clicks INT, Conversions INT); 

INSERT @x SELECT '12:00',2,0 
UNION ALL SELECT '13:00',3,2 
UNION ALL SELECT '14:00',1,1; 

;WITH x AS 
(
    SELECT n = ROW_NUMBER() OVER (ORDER BY s1.[object_id]) FROM sys.all_columns AS s1 
    -- CROSS JOIN (SELECT 1 UNION ALL SELECT 2) AS s2 -- to double the rows if you need more 
), 
y AS 
(
    SELECT [Hour], Conversions, Clicks, 
    m = MAX(CASE WHEN Conversions > Clicks THEN Conversions ELSE Clicks END) 
    FROM @x GROUP BY [Hour], Conversions, Clicks 
) 
SELECT y.[Hour], 
    Clicks = CASE WHEN Clicks < x.n THEN 0 ELSE 1 END, 
    Conversions = CASE WHEN Conversions < x.n THEN 0 ELSE 1 END 
FROM x INNER JOIN y ON x.n <= y.m 
ORDER BY CONVERT(TIME, y.[Hour]), Clicks, Conversions; 
2

Questo non è l'approccio più efficiente, ma potrebbe essere sufficiente per iniziare.

DECLARE @T TABLE (
    Hour   TIME 
    , Clicks  INT 
    , Conversions INT 
); 

INSERT @T VALUES ('12:00', 2, 0); 
INSERT @T VALUES ('1:00', 3, 2); 
INSERT @T VALUES ('2:00', 1, 1); 


DECLARE @Stage TABLE (
    Hour   TIME 
    , Clicks  INT 
    , Conversions INT 
); 

DECLARE @MaxClicks INT; 

SELECT @MaxClicks = MAX(Clicks) FROM @T; 

DECLARE @ClickCount INT; SET @ClickCount = 1; 

WHILE @ClickCount <= @MaxClicks 
BEGIN 
    INSERT @Stage (Hour, Clicks, Conversions) 
    SELECT Hour, 1, CASE WHEN Conversions >= @ClickCount THEN 1 ELSE 0 END 
    FROM @T WHERE Clicks >= @ClickCount; 

    SET @ClickCount = @ClickCount + 1; 
END; 

SELECT * FROM @Stage ORDER BY Hour; 
+0

Sebbene improbabile (e lo so solo perché ho familiarità con il tipo di modello dati), cosa succede se le conversioni sono superiori ai clic per una certa ora? per esempio. è possibile che qualcuno abbia fatto clic su 3:59 e acquistato alle 4:01. –

+0

Punto preso ... Immagino che il tuo approccio al tavolo di controllo sarebbe anche più efficiente. – JSR

+0

Penso di sì. Ma per favore chiama una tabella di numeri. Non sta contando nulla. :-) –

0
DECLARE @x TABLE ([Hour] TIME, Clicks INT, Conversions INT); 
INSERT @x VALUES ('12:00',2,0),('13:00',3,2), ('14:00',1,1); 

;WITH a as 
(
SELECT [hour], 1 [unnessasary column], clicks, CASE WHEN clicks <= Conversions THEN 1 ELSE 0 END click, Conversions 
FROM @x 
UNION ALL 
SELECT [hour], 1, clicks-1,CASE WHEN clicks-1 <= Conversions THEN 1 ELSE 0 END, Conversions 
FROM a 
WHERE clicks > 1 
) 
SELECT [hour],[unnessasary column], click 
FROM a 
ORDER BY 1 
OPTION (maxrecursion 0)