2009-05-09 15 views
15

habe ich eine Tabelle, wie untenSQL: Mit Top-1 in UNION-Abfrage mit Sortierung nach

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 

soll ich die alle Preise finden, die für das aktuelle Datum wirksam sind und danach. So, um den aktuellen effektiven Zinssatz zu bekommen, ich benutze

SELECT TOP 1 * from table 
where effective_date < '05/05/2009' 
order by effective date desc 

für die Preise nach dem aktuellen Datum der Abfrage

SELECT * from table 
where effective_date > '05/05/2009' 

Um diese beiden Ergebnisse kombinieren i verwenden, um eine Vereinigung als

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' 

Das erwartete Ergebnis ist

Rate Effective Date 
---- -------------- 
5.8 05/01/2009 
5.4 06/01/2009 
5.8 12/01/2009 
6.0 03/15/2009 

Aber ich habe das tatsächliche Ergebnis wie

Rate Effective Date 
---- -------------- 
5.6 02/02/2009 
5.4 06/01/2009 
5.8 12/01/2009 
6.0 03/15/2009 

Ich habe keine Ahnung, warum dies geschieht? Irgendwelche Vorschläge?

+1

Ich bin nicht sicher, dass Ihre "erwarteten" Ergebnisse tatsächlich die Ergebnisse sind, die Sie erwarten sollten. 3/15/2009 ist der "vorletzte" "aktuellste vorherige" Datensatz vor Ihrem Suchdatum von '5/5/2009 '.. Sie sollten nur 3 Datensätze in Ihrer erwarteten Ergebnismenge erhalten. – datacop

Antwort

24

Es funktioniert so:

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' 
+0

Wird in diesem Fall das Problem, dass "top x" in einer Abfrage der Union nicht berücksichtigt wird, behandelt? (Ich nehme an, es tut, aber habe nicht mit MSSS gespielt) – Karl

+0

Ja, das funktioniert. Ich habe es gegen SQL Server 2005 getestet. – splattne

+0

Ja, die bearbeitete Version Ihrer Antwort funktioniert (um die Reihenfolge von Abfrage in einer nicht geordneten Abfrage für die Union umbrechen). Wie bei Katzen gibt es ein Dutzend verschiedene Arten, sie zu häuten. Ich habe Ihre Suchanfrage überprüft, um die gleichen Ergebnisse wie meine zurückzugeben. Dein ist großartig für schnelle und dreckige "Gimmie die Daten jetzt" -Situationen ... Ich mag die CTE-Methode, die ich beschrieben habe, denn wenn es einmal geschrieben ist, kannst du mit den Daten alles machen, was du willst. (Geben Sie mir also die zweithöchste Rate [aber nicht die vorherige] und alle "aktuellen" Raten) – datacop

1

Ich glaube, die obigen Abfragen sind ausgeschlossen 05/01/2009 mit < und> statt < = und> =.

7

Die Sortierung nach in einer select-Anweisung, die Teil einer Vereinigung ist, wird ignoriert. Daher wählt Ihr TOP 1 einen beliebigen Datensatz aus (wahrscheinlich der erste Datensatz nach dem gruppierten Schlüssel für die Tabelle).

+0

Genau und gut gesagt. Ich bin genau auf dieses Problem gestoßen. –

2

Order By ist ungültig, wenn es mit einer Union verwendet ...

I Common Table Expression mit einem gewissen Rang und Case-Anweisung Tricks einen Quickie und schmutzig Dingen mit aufgearbeitet, um die Ergebnisse zu erhalten Sie ..

waren auf der Suche
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 

Um zu erklären, was passiert ...

der CTE der Rate von der Abfrage zurückgegeben, Datum, aktuelle und Sortier-Flags definiert ...

Der CASE trennt die Ergebnisse in diejenigen, die vor dem Suchdatum liegen, und diejenigen, die nach dem Suchdatum liegen. Wir verwenden die Ergebnisse aus der Groß-/Kleinschreibung in unserer Vereinigung, um die Ergebnisse aus der partitionierten Liste zu ziehen.

Die Rank() -Funktion sortiert dann die Liste, indem sie eine Partition nach den gleichen Kriterien erstellt, die die CASE-Anweisung verwendet, um die Liste zu trennen. Dann sortieren wir nach dem effektiven Datum absteigend. Dies wird die „Vergangenheit“ Liste nehmen und es am aktuellen „Vergangenheit“ -Eintrag Rang 1 ..

Dann in der Union Teil der Abfrage machen ..

Im oberen Teil, wir bekommen den Rang und Datum von der "Vergangenheit" -Liste (cur = 0) und dem ersten Eintrag in der "Past" -Liste. (sort = 1) .. das wird 1 record (oder 0, wenn es keine Datensätze gibt, die vor dem sind Suchdatum) ..

Dann wir Vereinigung, dass mit all dem Datensatz aus der „aktuellen“ Liste (Aktuell = 1)

Dann endlich .. nehmen wir die Ergebnisse der UNION .. und damit die von dem Stichtag geben alle aktuellen Datensätze und der "aktuellste" vorherige Datensatz.