Ich arbeite mit einem Lebensmitteleinkaufs- / Rechnungssystem in MS Access 2013 und versuche, eine SQL-Abfrage zu erstellen, die den letzten Kaufpreis für jedes einzelne Lebensmittel zurückgibt.
Hier ist ein Diagramm der Tabellen, mit denen ich arbeite:
Mein Verständnis von SQL ist sehr grundlegend, und ich habe die folgende (falsche) Abfrage versucht, in der Hoffnung, dass nur ein Datensatz pro Artikel (aufgrund des DISTINCT
Operators) zurückgegeben wird und nur der letzte Kauf zurückgegeben wird (seit ich dies getan habe) ORDER BY [Invoice Date] DESC
)
SELECT DISTINCT ([Food items].Item),
[Food items].Item, [Food purchase data].[Price per unit], [Food purchase data].[Purchase unit], Invoices.[Invoice Date]
FROM Invoices
INNER JOIN ([Food items]
INNER JOIN [Food purchase data]
ON [Food items].ID = [Food purchase data].[Food item ID])
ON Invoices.ID = [Food purchase data].[Invoice ID]
ORDER BY Invoices.[Invoice Date] DESC;
Die obige Abfrage gibt jedoch einfach alle Lebensmitteleinkäufe zurück (dh mehrere Datensätze für jeden Datensatz in [Food items]
), wobei die Ergebnisse nach Datum sortiert sind. Kann mir jemand erklären, was ich über den DISTINCT
Betreiber falsch verstehe? Das heißt, warum wird nicht nur ein Datensatz für jeden Artikel in zurückgegeben [Food items]
?
Und mehr auf den Punkt gebracht - was ist für mich die einfachste Möglichkeit, die neuesten Daten zum Lebensmitteleinkauf für jedes einzelne Lebensmittel zu ermitteln, wenn man die oben gezeigte Tabellenstruktur berücksichtigt ? Effizienz ist mir weniger wichtig als Einfachheit (die Datenbank, mit der ich arbeite, ist eher klein - es wird Jahre dauern, bis sie überhaupt im Bereich von Zehntausenden von Datensätzen liegt). Es ist mir wichtiger, dass die Abfrage für jemanden mit geringen SQL-Kenntnissen verständlich ist.
UPDATE: Also habe ich versucht, beide unten vorgeschlagenen Antworten zu verwenden, und keine funktioniert (sie werfen nur Syntaxfehler auf).
Basierend auf den folgenden Vorschlägen und der Online-Lektüre habe ich die folgende neue Abfrage unter Verwendung der Aggregatfunktion max()
und einer GROUP BY
Klausel geschrieben:
SELECT [Food purchase data].[Food item ID], [Food purchase data].[Price per unit], max(Invoices.[Invoice Date]) AS MostRecentInvoiceDate
FROM [Food purchase data], Invoices
GROUP BY [Food purchase data].[Food item ID], [Food purchase data].[Price per unit];
Aber ich habe immer noch das gleiche Problem: Das heißt, ich sehe immer noch mehr als ein Ergebnis für jedes Lebensmittel. Kann jemand erklären, warum diese Abfrage nicht nur den letzten Kauf für jedes Lebensmittel zurückgibt?
UPDATE 2 (Gelöst!) :
Keine der folgenden Antworten hat ganz geklappt, aber aufgrund einer starken Änderung der Antwort von Vladimir konnte ich die folgenden Abfragen erstellen, die anscheinend die richtigen Ergebnisse liefern.
Zuerst habe ich diese Ansicht erstellt und sie "LatestInvoices" genannt:
SELECT InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate, InvoicesMaxDate.MaxID
FROM [Food purchase data], Invoices, (SELECT [Food purchase data].[Food item ID] AS ItemID, MAX(Invoices.[Invoice Date]) AS MaxDate, MAX(Invoices.[Invoice ID]) AS MaxID
FROM [Food purchase data], Invoices
WHERE Invoices.[Invoice ID] = [Food purchase data].[Invoice ID]
GROUP BY [Food purchase data].[Food item ID]
) AS InvoicesMaxDate
WHERE InvoicesMaxDate.MaxID = [Food purchase data].[Invoice ID] AND
InvoicesMaxDate.ItemID = [Food purchase data].[Food item ID] AND
InvoicesMaxDate.MaxDate = Invoices.[Invoice Date]
GROUP BY InvoicesMaxDate.ItemID, InvoicesMaxDate.MaxDate, InvoicesMaxDate.MaxID
Dann schrieb ich eine weitere Abfrage, um die Felder einzugeben, die ich brauchte:
SELECT [Food items].ID AS FoodItemID, [Food items].Item AS FoodItem, [Food purchase data].[Price], [Food purchase data].[Price per unit], [Food purchase data].[Purchase unit], LatestInvoices.MaxDate as InvoiceDate
FROM [Food items], [Food purchase data], LatestInvoices
WHERE LatestInvoices.[MaxID] = [Food purchase data].[Invoice ID] AND
LatestInvoices.ItemID = [Food purchase data].[Food item ID] AND
LatestInvoices.ItemID = [Food items].ID
ORDER BY [Food items].Item;
Vielen Dank an alle, die sich die Zeit genommen haben, mir dabei zu helfen!
[
und]
ID
Spalten aufzunehmen, damit ID
in die Invoices
Tabelle wird InvoiceID
.
DISTINCT
das wäre aus einzelnen Spalten. Gibt es einen analogen Operator, der nur anhand der Eindeutigkeit in einer einzelnen Spalte auswählt? Vielen Dank auch für die Tipps zu Namenskonventionen - ja, es ist sehr ärgerlich, sie [ ... ]
überall verwenden zu müssen ... Und ich kann sehen, wie die Aufnahme des Tabellennamens in die ID-Spalte die Lesbarkeit verbessern würde.
DISTINCT
Gibt Zeilen zurück, die für alle Spalten in der Zeile unterschiedlich sind, nicht für einzelne Spalten.