SQL:Utilizzo di Top 1 nella query UNION con Ordina per
-
20-08-2019 - |
Domanda
Ho una tabella come di seguito
Rate Effective_Date
---- --------------
5.6 02/02/2009
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Dovrei trovare tutte le tariffe in vigore per la data corrente e successivamente.Quindi, per ottenere il tasso effettivo attuale, utilizzo
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
per le tariffe successive alla data corrente la query è
SELECT * from table
where effective_date > '05/05/2009'
Per combinare questi due risultati utilizzo un'unione as
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
UNION
SELECT * from table
where effective_date > '05/05/2009'
Il risultato atteso è
Rate Effective Date
---- --------------
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Ma ottengo il risultato effettivo come
Rate Effective Date
---- --------------
5.6 02/02/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Non ho la più pallida idea del perché questo accada?Eventuali suggerimenti?
Soluzione
Funziona in questo modo:
select *
from (
select top 1 *
from table
where effective_date <= '05/05/2009'
order by effective_date desc
) as current_rate
union all
select *
from table
where effective_date > '05/05/2009'
Altri suggerimenti
ORDER BY in un'istruzione SELECT che fa parte di un'unione viene ignorato. Quindi il vostro TOP 1 è la selezione di alcuni record di arbitrario (probabilmente il primo record dalla chiave cluster per la tabella).
Ordina per non è valido se utilizzato con un'Unione...
Ho elaborato una cosa veloce e sporca utilizzando l'espressione di tabella comune con alcuni trucchi con le istruzioni Rank e Case per ottenere i risultati che stavi cercando.
WITH CTE_RATES ( RATE, EFFECTIVE_DATE, CUR, SORT )
AS (
SELECT
Rate,
Effective_date,
CASE WHEN Effective_date > '5/5/2009' THEN 1
ELSE 0
END,
RANK() OVER (PARTITION BY
CASE WHEN EFFECTIVE_DATE > '5/5/2009' THEN 1
ELSE 0
END
ORDER BY EFFECTIVE_DATE DESC)
FROM TestTable
)
SELECT RATE, EFFECTIVE_DATE
FROM (
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 0 AND SORT = 1
UNION ALL
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 1
) AS QRY
ORDER BY EFFECTIVE_DATE
Per spiegare cosa sta succedendo...
Il CTE definisce la frequenza, la data, i flag correnti e di ordinamento restituiti dalla query...
Il CASE separa i risultati in quelli precedenti alla data di ricerca e quelli successivi alla data di ricerca.Utilizziamo i risultati del caso (Cur) nella nostra unione per estrarre i risultati dall'elenco partizionato.
La funzione Rank() ordina quindi l'elenco creando una partizione in base agli stessi criteri utilizzati dall'istruzione CASE per separare l'elenco.quindi ordiniamo in base alla data di entrata in vigore in modo decrescente.Questo prenderà l'elenco "passato" e renderà la sua voce "passata" più recente al livello 1..
Quindi nella parte di unione della query...
Nella parte superiore otteniamo il rango e la data dall'elenco "passato" (cur = 0) e la prima voce nell'elenco "passato".(ordinamento = 1)..ciò restituirà 1 record (o 0 se non sono presenti record precedenti alla data di ricerca).
Quindi lo uniamo a tutto il record dell'elenco "corrente" (cur = 1)
Poi finalmente..prendiamo i RISULTATI dell'UNIONE..e ordinarlo entro la data di entrata in vigore fornendoci tutti i record attuali e il record precedente "più recente".
Credo che le query di cui sopra sono esclusi 05/01/2009 utilizzando lt &; e GT &; invece di lt &; = e gt &;. =