Ich habe eine Tabelle mit Bestellungen
Column | Type | Modifiers
------------+-----------------------------+-----------------------------------------------------
id | integer | not null default nextval('orders_id_seq'::regclass)
client_id | integer | not null
start_date | date | not null
end_date | date |
order_type | character varying | not null
Die Daten haben nicht überlappende Daueraufträge für eine client_id und gelegentlich einen temporären Auftrag, der den Dauerauftrag am Startdatum überschreibt, wenn sie eine übereinstimmende client_id haben. Es gibt Einschränkungen auf Anwendungsebene, die verhindern, dass sich Aufträge desselben Typs überschneiden.
id | client_id | start_date | end_date | order_type
----+-----------+------------+------------+------------
17 | 11 | 2014-02-05 | | standing
18 | 15 | 2014-07-16 | 2015-07-19 | standing
19 | 16 | 2015-04-01 | | standing
20 | 16 | 2015-07-18 | 2015-07-18 | temporary
Zum Beispiel hat auf 2015-07-18
Client 16 die Bestellung Nr. 20 als aktive Bestellung, da sie den Dauerauftrag Nr. 19 überschreibt. Mit einigem Aufwand fand ich eine effiziente Möglichkeit, aktive Bestell-IDs an einem Datum abzufragen.
SELECT id from (
SELECT
id,
first_value(id) OVER (PARTITION BY client_id ORDER BY order_type DESC) active_order_id
FROM orders
WHERE start_date <= ? and (end_date is null OR end_date >= ?)
) active_orders
WHERE id = active_order_id
Wenn Sie dies 2015-07-18
als Platzhalter abfragen , erhalten Sie
id
----
17
18
20
Der Abfrageplan für diese Abfrage ist im Vergleich zu einigen meiner anderen Ideen (z. B. Unterabfragen, bei denen die Anzahl der temporären Bestellungen für einen Kunden an einem Datum gezählt wird) recht klein und ich bin ziemlich zufrieden damit. (Das Design des Tisches, ich bin nicht begeistert)
Jetzt muss ich alle aktiven Bestellungen für einen Datumsbereich finden, die mit den Daten verknüpft sind, an denen sie aktiv sind. Zum Beispiel möchte ich mit dem Datumsbereich von 2015-07-18
bis 2015-07-19
das folgende Ergebnis.
active_date | id
------------+----
2015-07-18 | 17
2015-07-18 | 18
2015-07-18 | 20
2015-07-19 | 17
2015-07-19 | 18
2015-07-19 | 19
Bestellung 20 überschreibt Bestellung 19 ein, 2015-07-18
aber nicht ein 2015-07-19
.
Ich habe festgestellt, dass generate_series()
ich eine Reihe von Daten generieren kann, aber ich habe keine Ahnung, wie ich das damit verbinden soll, um eine Tabelle mit Daten und Bestell-IDs zu erhalten. Meine Vermutung ist ein Cross Join, aber ich kann nicht herausfinden, wie das unter diesen Umständen funktioniert.
Vielen Dank
UPDATE Es wurde eine SQL-Geige hinzugefügt .
quelle
Antworten:
Ich würde
select distinct on
anstelle der Fensterfunktion verwenden, dann einfach die Tage verbinden.http://sqlfiddle.com/#!15/5a420/16/0
Ich kann mehr ausarbeiten, wenn etwas nicht klar ist.
quelle
distinct on
ist noch optimierter als die Fensterabfrage. Übrigens sollte ich erwähnen, dass dies ein häufiges "Top-in-Group" -Problem in SQL ist: stackoverflow.com/questions/3800551/…Schreiben Sie eine Funktion, die ein einzelnes Datum als Parameter verwendet und eine Liste von Datums- und IDs mit einer Reihenfolge zurückgibt.
Verwenden Sie dann die von Ihnen vorgeschlagene generate_series und rufen Sie die Funktion über den Datumsbereich auf.
Dies ist eine gängige Strategie beim Umgang mit komplexen Bedingungen in SQL.
Ich habe unten Code eingefügt, aber die obige SQL-Antwort ist viel einfacher.
Hier ist die Funktion:
Und wie man es nennt:
SQLFiddle
quelle