rene1976
Goto Top

MS-SQL - wie kann man in der where Bedingung nur den ersten Datensatz (TOP 1) ermitteln?

Hallo,

wir nutzen den MS-SQL Server 2012.
Für eine Abfrage über mehrere Tabellen brauche ich als Ergebnis der Unterabfrage nur den letzen Datensatz seine Anfrage pro Kunden zurück.
Dieser wird dann über die Kundennummer wieder mit zwei anderen Tabelle verknüpft.

Frage:
Gibt es die Möglichkeit in einer Abfrage in der where Bedingung als Ergebnis nur die letzte Anfrage eines Kunden in einen Anfragezeitraum zurückzuliefern, so wie am es sonst mit "select TOP 1 ... order by desc" für die ganze Tabelle hinbekommt.
In diesem Fall soll das Ergebnis aber nur die letzte Anfrage pro Kunden und nicht pro Tabelle zurückgegeben werden.

Meine Unterabfrage sieht so aus:

select kdnr from tblwebBuchungen
WHERE herkunft in ('www.domain1.de','www.domain2.de', 'www.domain3.de')
and (anfrageDatum >= '01.10.2016')
AND (anfrageDatum <= '31.10.2017')

Da ein Kunde mehrere Anfrage in den Anfragezeitraum gemacht haben kann, brauche ich jetzt in der where Bedingung zusätzlich so etwas wie "TOP 1 order by anfrageDatum desc" .
Als Ergebnis würde dann eine Liste mit allen Kunden und ihren LETZTEN Anfragen in den Zeitraum herauskommen.

Dies würde ich später wieder mit zwei weiteren Tabellen verknüpfen um der letzten Anfrage des jeweiligen Kunden mit seiner letzten Buchungen zu verknüpfen.

Die ganze Abfrage sieht so aus. Leider konnte es eben zu doppelten Buchungen bei Kunden die mehrere Anfragen gemacht haben, aber nur einmal gebucht haben.
Die Ursache liegt in der Tabelle tblwebBuchungen. Hier brauche ich nur die letzte Anfrage pro Kunde:

SELECT vorgang.kdnr, buchungen.idBuchnr, tblwebBuchungen.objektNr, buchungen.mietpr, tblwebBuchungen.herkunft,
FROM vorgang INNER JOIN
tblwebBuchungen ON vorgang.kdnr = tblwebBuchungen.kdnr INNER JOIN
buchungen ON vorgang.idBuchNr = buchungen.idBuchnr
WHERE (tblwebBuchungen.herkunft = 'www.domain1.de')
AND (vorgang.vgart = 'BU') AND (vorgang.von >= '01.01.2017')
AND (vorgang.bis <= '31.12.2017')
AND (tblwebBuchungen.anfrageDatum >= '01.10.2016')
AND (tblwebBuchungen.anfrageDatum <= '31.10.2017')
ORDER BY vorgang.kdnr DESC

Besten Dank,

Rene

Content-Key: 352349

Url: https://administrator.de/contentid/352349

Printed on: April 19, 2024 at 19:04 o'clock

Member: ukulele-7
ukulele-7 Oct 20, 2017 at 10:12:46 (UTC)
Goto Top
Ich würde das so machen:
SELECT	t.kdnr, t.idBuchnr, t.objektNr, t.mietpr, t.herkunft
FROM	(

SELECT	ROW_NUMBER() OVER (PARTITION BY vorgang.kdnr ORDER BY buchungen.idBuchnr DESC) AS zeile,
		vorgang.kdnr, buchungen.idBuchnr, tblwebBuchungen.objektNr, buchungen.mietpr, tblwebBuchungen.herkunft
FROM	vorgang
INNER JOIN tblwebBuchungen
ON		vorgang.kdnr = tblwebBuchungen.kdnr
INNER JOIN buchungen
ON		vorgang.idBuchNr = buchungen.idBuchnr
WHERE	tblwebBuchungen.herkunft = 'www.domain1.de'  
AND		vorgang.vgart = 'BU'  
AND		vorgang.von >= '01.01.2017'  
AND		vorgang.bis <= '31.12.2017'  
AND		tblwebBuchungen.anfrageDatum BETWEEN '01.10.2016' AND '31.10.2017'  

		) t
WHERE	t.zeile = 1
ORDER BY t.kdnr DESC
ROW_NUMBER() in einem Subselect ist auf jedenfall ein richtiger Weg. Ob die Paritionierung und die Sortierung richtig sind müsstest du mal anhand deiner Daten prüfen.
Member: MadMax
MadMax Oct 20, 2017 at 11:11:03 (UTC)
Goto Top
Hallo Rene,

die von ukulele vorgeschlagene row_number ist zwar eine Möglichkeit, aber nicht die schnellste. Besser ist da sowas wie "cross apply":
SELECT	vorgang.kdnr, buchungen.idBuchnr, tblwebBuchungen.objektNr, buchungen.mietpr, tblwebBuchungen.herkunft,
FROM	vorgang
	cross apply (
		select	top (1) *
		from	tblwebBuchungen
		where	kdnr = vorgang.kdnr
			and herkunft = 'www.domain1.de'  
			and anfrageDatum between '01.10.2016' and '31.10.2017'  
		order by anfrageDatum desc
		) as tblwebBuchungen
	INNER JOIN buchungen ON vorgang.idBuchNr = buchungen.idBuchnr
WHERE	(vorgang.vgart = 'BU')  
	AND (vorgang.von >= '01.01.2017')  
	AND (vorgang.bis <= '31.12.2017')  
ORDER BY vorgang.kdnr DESC

Gruß, Mad Max