2011-12-16 16 views
5

Ho la seguente tabella:ricorsivo CTE - consolidare inizio e di fine

row_num customer_status effective_from_datetime 
------- ------------------ ----------------------- 
1  Active    2011-01-01 
2  Active    2011-01-02 
3  Active    2011-01-03 
4  Suspended   2011-01-04 
5  Suspended   2011-01-05 
6  Active    2011-01-06 

e sto cercando di ottenere il seguente risultato cui righe consecutive con lo stesso stato sono fusi in una riga con un efficace da e per Periodo:

customer_status effective_from_datetime effective_to_datetime 
--------------- ----------------------- --------------------- 
Active   2011-01-01    2011-01-04 
Suspended  2011-01-04    2011-01-06 
Active   2011-01-06    NULL 

posso ottenere un CTE ricorsiva di uscita effective_to_datetime corretta in base riga successiva, ma sto avendo difficoltà fusione delle gamme.

codice per generare dati di esempio:

CREATE TABLE #temp 
(
row_num INT IDENTITY(1,1), 
customer_status VARCHAR(10), 
effective_from_datetime DATE 
) 

INSERT INTO #temp 
VALUES 
('Active','2011-01-01') 
,('Active','2011-01-02') 
,('Active','2011-01-03') 
,('Suspended','2011-01-04') 
,('Suspended','2011-01-05') 
,('Active','2011-01-06') 
+0

Oh, e non voglio usare un cursore o un ciclo perché il piano è di usare questa logica in una vista. – shakedown7

+0

Cosa succede se non si dispone di una voce per una data? Dovrebbe essere considerato come una lacuna nella sequenza? per esempio. supponiamo che la riga '('Active', '2011-01-02')' non fosse presente? –

risposta

8

EDIT SQL aggiornato come da commento.

WITH 
    group_assigned_data AS 
(
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY customer_status ORDER BY effective_from_date) AS status_sequence_id, 
    ROW_NUMBER() OVER (       ORDER BY effective_from_date) AS sequence_id, 
    customer_status, 
    effective_from_date 
    FROM 
    your_table 
) 
, 
    grouped_data AS 
(
    SELECT 
    customer_status, 
    MIN(effective_from_date) AS min_effective_from_date, 
    MAX(effective_from_date) AS max_effective_from_date 
    FROM 
    group_assigned_data 
    GROUP BY 
    customer_status, 
    sequence_id - status_sequence_id 
) 
SELECT 
    [current].customer_status, 
    [current].min_effective_from_date  AS effective_from, 
    [next].min_effective_from_date   AS effective_to 
FROM 
    grouped_data AS [current] 
LEFT JOIN 
    grouped_data AS [next] 
    ON [current].max_effective_from_date = [next].min_effective_from_date + 1 
ORDER BY 
    [current].min_effective_from_date 

Questo non è ricorsivo, ma forse è una buona cosa.


Non si tratta con le lacune nei dati. Per far fronte a ciò, è possibile creare una tabella di calendario, con ogni data rilevante, e unirsi a quella per riempire le date mancanti con lo stato 'sconosciuto', e quindi eseguire la query su tale. (Infatti, si cate farlo un CTE che viene utilizzato dal CTE sopra).

Attualmente ...
- Se riga 2 mancava, non cambierebbe il risultato
- Se riga 3 mancava, l'end_date della prima fila cambierebbe

comportamento differente può essere determinato preparando i tuoi dati, o altri metodi. Dovremmo però conoscere la logica di business di cui hai bisogno.


Se uno qualsiasi data può avere più voci di stato, è necessario definire quale logica si desidera seguire. Al momento il comportamento non è definito, ma è possibile correggerlo semplicemente aggiungendo customer_status alle porzioni ORDER BY di ROW_NUMBER().

+0

Perfetto - grazie! – shakedown7

+0

L'unico problema che vedo (che a mio parere rende la soluzione completamente diversa) - l'efficace_to_datetime dovrebbe essere uguale a effective_from_datetime della riga successiva. – shakedown7

+0

@ shakedown7 - Questa è la situazione di "gap" a cui mi riferisco. Se hai delle lacune che la soluzione più semplice è quella di SINISTRA Accedi a una tabella del calendario per riempire gli spazi vuoti. Ciò causerà la visualizzazione di tre tipi di gruppi, uno dei quali si riferisce ai tuoi spazi vuoti, e puoi dare un nome o scegliere di filtrare in seguito. – MatBailie

Problemi correlati