emeriks
Goto Top

Hilfe bei SQL-Abfrage

Hi,
gegeben:
  • MS SQL Server 2005
  • eine DB mit 3 Tabellen

Tabelle "Objekte"
  • 2 Spalten: ID, Name

Tabelle "Eigenschaften"
  • 3 Spalten: ID, ObjektID, Name

Tabelle "Werte"
  • 4 Spalten: ID, EigenschaftID, Wert, Datum

Ich habe verschiedene Objekte mit mehreren, verschiedenen Eigenschaften. Jedes Mal, wenn eine Eigenschaft eines Objekts geändert wird, dann soll der verherige Wert (und alle anderen, vorherigen) erhalten bleiben. Dazu wird in "Werte" ein neuer Datensatz erstellt, "ID" automatisch, "EigenschaftID" die ID der geänderten Eigenschaft, "Wert" der neue Wert und "Datum" das aktuelle Datum.

Wie kann ich jetzt mit jetzt alle Eigenschaften eines Objekts mit nur den aktuellsten Wert abfragen?

Was ich schon hinbekommen habe: Die Eigenschaften mit jeweils dem Datum des aktuellsten Werts liefern lassen.
SELECT [Objekte].[Name], [Eigenschaften].[Name], Max([Werte].[Datum]) AS [MaxDatum]
FROM   [Objekte]
INNER JOIN  [Eigenschaften] ON [Eigenschaften].[ObjektID] = [Objekte].[ID]
INNER JOIN  [Werte] ON [Werte].[EigenschaftID] = [Eigenschaften].[ID]
GROUP BY [Objekte].[Name], [Eigenschaften].[Name]

Aber wie bekomme ich es hin, dass er mir statt dem max. Datum den Wert liefert?

Folgendes funktioniert nicht:
SELECT [Objekte].[Name], [Eigenschaften].[Name], [Werte].[Wert]
FROM   [Objekte]
INNER JOIN  [Eigenschaften] ON [Eigenschaften].[ObjektID] = [Objekte].[ID]
INNER JOIN  [Werte] ON [Werte].[EigenschaftID] = [Eigenschaften].[ID]
WHERE [Werte].[Datum] = Max([Werte].[Datum]) 
GROUP BY [Objekte].[Name], [Eigenschaften].[Name]

Da kommt:
In der WHERE-Klausel darf kein Aggregat auftreten, es sei denn, es befindet sich in einer Unterabfrage, die in einer HAVING-Klausel oder einer Auswahlliste enthalten ist, und die Spalte, die aggregiert wird, ist ein äußerer Verweis.

Wie muss ich da vorgehen?

E.

Content-ID: 330174

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

Ausgedruckt am: 25.11.2024 um 14:11 Uhr

MadMax
Lösung MadMax 22.02.2017 um 12:25:41 Uhr
Goto Top
Hallo Emerics,

gab es bei SQL Server 2005 schon sowas wie "cross apply"? Dann würde das so funktionieren:
 
SELECT [Objekte].[Name], [Eigenschaften].[Name], [Werte].[Datum], Werte.Wert
FROM   [Objekte]
INNER JOIN  [Eigenschaften] ON [Eigenschaften].[ObjektID] = [Objekte].[ID]
cross apply (select top (1) * from Werte where EigenschaftID = Eigenschaften.ID order by ID desc) as Werte

Ansonsten konnte man das früher so machen:
SELECT [Objekte].[Name], [Eigenschaften].[Name], [Werte].[Datum], Werte.Wert
FROM   [Objekte]
INNER JOIN  [Eigenschaften] ON [Eigenschaften].[ObjektID] = [Objekte].[ID]
INNER JOIN  [Werte] ON [Werte].[ID] = (select top (1) ID from Werte where EigenschaftID = Eigenschaften.ID order by ID desc)

Gruß, Mad Max
emeriks
emeriks 22.02.2017 um 13:52:30 Uhr
Goto Top
Danke MadMax!

Zuerst: Habe mich vertan: Es ist ein SQL 2012. Sorry

Der zweite Ansatz funktioniert. Nur will ich mich hier nicht darauf verlassen, dass immer jener Datensatz mit der höchsten ID auch das jüngste Datum hat. Also mach ich hier ein "ORDER BY [Werte].[Datum] DESC".

Der Ansatz mit dem Cross Apply liefert mir nur 2 Spalten: Objekte.Name und Eigenschaften.Name
Wenn ich hier im oberen SELECT das "[Werte].[Wert]" drin lasse, dann kommt
Der mehrteilige Bezeichner 'Werte.Wert' konnte nicht gebunden werden.
Lass ich es weg, dann läuft die Abfrage, aber eben nur mit den 2 o.g. Spalten.

Aber egal. Der Ansatz ohne das CROSS APPLY funktioniert und hilft mir weiter.

Danke!
em-pie
em-pie 22.02.2017 aktualisiert um 14:00:05 Uhr
Goto Top
Moin,

der Grund, warum dein zweites Statement nicht läuft ist der, dass du im SELECT-Segment das Feld [WERTE].[WERT] darstellen willst, es aber in die GROUP BY Clause nicht mit eingebunden hast.

Ansonsten müsstest du mit einem SubSelect im Inner Join arbeiten
Versuche das mal (ist nur "mal eben" zusammengedengelt):
SELECT 
	[Objekte].[Name]
	, [Eigenschaften].[Name]
	, [Tbl02].[Wert]
FROM 
	[Eigenschaften]
INNER JOIN  [Objekte] ON 
	[Eigenschaften].[ObjektID] = [Objekte].[ID]
INNER JOIN	(
		SELECT [EigenschaftenID], [Wert], MAX[Datum] as MaxDatum
		FROM Werte
		GROUP BY [Datum]
		) as Tbl02 ON
	[Eigenschaften].[ID] = [Tbl02].[Werte]

Gruß
em-pie

Edit: zulange getippt face-big-smile
MadMax
Lösung MadMax 22.02.2017 um 14:30:53 Uhr
Goto Top
Hallo Emerics,

kann es sein, daß Du beim cross apply in der Unterabfrage auch "select top (1) Datum" geschrieben hast und nicht mehr "select top (1) *"? Beim cross apply solltest Du nur die Spalten im order by austauschen, nicht die Spalten im select.

Cross apply wird besser verarbeitet, deswegen solltest Du das verwenden.

Gruß, Mad Max
emeriks
emeriks 22.02.2017 um 14:38:20 Uhr
Goto Top
Jep! Das wars.
Habe jetzt "SELECT TOP 1 [Werte].[Wert]" und damit geht es.