Arbeiten die SQL aus einer Prioritätswarteschlange Tabelle abfragen
-
19-08-2019 - |
Frage
Ich bin die Umsetzung eine kleine Warteschlange zu handhaben, welcher Prozess zuerst ausgeführt wird. Ich verwende eine Tabelle in einer Datenbank, dies zu tun. Hier ist die Struktur der Tabelle (ich spöttisch es in SQLite up):
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,
"identifier" VARCHAR NOT NULL ,
"priority_number" INTEGER DEFAULT 15,
"timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP,
"description" VARCHAR
Ich versuche, SQL zu schreiben, mir die Zeile zu geben, von denen Prozess nächsten ausgeführt werden kann. Hier einige Beispieldaten:
id identifier priority_number timestamp description
1 test1 15 2009-01-20 17:14:49 NULL
2 test2 15 2009-01-20 17:14:56 NULL
3 test3 10 2009-01-20 17:15:03 NULL
4 test4 15 2009-01-20 17:15:08 NULL
5 test5 15 2009-01-20 17:32:23 NULL
6 test6 14 2009-01-20 17:32:30 NULL
7 test7 7 2009-01-20 17:32:38 NULL
8 test8 20 2009-01-20 17:32:57 NULL
9 test9 7 2009-01-21 13:47:30 NULL
10 test10 15 2009-01-21 13:50:52 NULL
Wenn ich diese SQL verwende, kann ich die Daten in der richtigen Reihenfolge erhalten:
select * from queue_manager order by priority_number, timestamp;
Das gibt mir das Element mit der niedrigsten Priorität Nummer (am wichtigsten) an der Spitze, und in diesen Prioritätszahlen, die frühestens in die Warteschlange (durch Zeitstempel) an der Spitze.
Ich konnte diese Abfrage ausführen, und nur die erste Zeile nehmen, aber ich würde lieber diese Abfrage mit SQL tun, die mir die einer Zeile des Prozesses geben würde, die (in den Beispieldaten an der Spitze der Warteschlange oben die Reihe mit id = 7).
Ich habe versucht, sich selbst zu tun Joins und Unterabfragen, aber ich muss eine mentale Blockade werden muss -. Ich kann einfach nicht richtig sein, es zu bekommen
Vielen Dank im Voraus!
Bearbeiten
Ich habe vergessen zu erwähnen, dass ich für eine Datenbank-unabhängige Abfrage suchen. Ich spöttischen dies in SQlite, aber es gibt eine gute Möglichkeit, die ich dies in DB2 oder Oracle implementieren wird. Ich hatte gedacht, eine „Grenze 1“ Typ Operator auf meine Anfrage zu verwenden, aber das ist etwas anderes zwischen verschiedenen Datenbank-Engines.
Lösung
Sehen Sie, wenn dies funktioniert:
select * from queue_manager where priority_number =
(select min(priority_number) from queue_manager) and
timestamp = (select min(timestamp)
from queue_manager qm2
where qm2.priority_number = queue_manager.priority_number)
Andere Tipps
select * from queue_manager order by priority_number, timestamp LIMIT 1;
Wie für eine solche genannte „Datenbank independency“, es ist ein Mythos für die meisten realen Welt Aufgaben. In der Regel können Sie nicht einmal Schema in der Datenbank unabhängig erstellen.
Wenn Sie es wünschen ‚Concurrent sicher‘ zu sein, auf so etwas wie InnoDB tun:
1) Fügen Sie ein 'IN_PROGRESS' Feld.
2) Schalten Sie autoCommit
3) SELECT * FROM queue_manager wo IN_PROGRESS = 0, um durch priority_number, Zeitstempel- LIMIT 1 FOR UDPATE;
4) UPDATE queue_manager IN_PROGRESS SET = 1 wobei id = X;
5) COMMIT
6) die Arbeit machen. Dann löschen Sie die Zeile, wenn seine zur Zufriedenheit erledigt. Haben Sie einen 'Master-Prozess' Griff / redelegate / aufzuräumen alten "IN_PROGRESS Arbeitsplätze.
Der beste Weg, dies zu tun ist, Datenbank abhängig ist; es ist eine viel einfachere Sache im Vergleich zu all den Overhead-Cursor oder andere Konstrukte unterschiedliche Retrieval Procs für die verschiedenen Ziel DBMS zu haben.
Die Auswahl eine begrenzte Anzahl von Zeilen in verschiedenen Geschmacksrichtungen von SQL anders gemacht wird, so dass je nach dem Sie es verwenden könnte ein in Art und Weise aufgebaut sein, es zu tun. Zum Beispiel in MS SQL Server:
SELECT TOP 1
identifier,
priority_number,
timestamp,
description
FROM
dbo.Queue_Manager
ORDER BY
priority_number,
timestamp
Diese kompatible SQL in ANSI zu tun, sollten die folgenden Methoden arbeiten:
SELECT
QM1.identifier,
QM1.priority_number,
QM1.timestamp,
QM1.description
FROM
Queue_Manager QM1
LEFT OUTER JOIN Queue_Manager QM2 ON
QM2.priority_number < QM1.priority_number OR
(QM2.priority_number = QM1.priority_number AND QM2.timestamp < QM1.timestamp)
/* If you're concerned that there might be an exact match by priority_number
and timestamp then you might want to add a bit more to the join */
WHERE
QM2.identifier IS NULL
Oder Sie können versuchen:
SELECT
QM1.identifier,
QM1.priority_number,
QM1.timestamp,
QM1.description
FROM
Queue_Manager QM1
INNER JOIN
(
SELECT
priority_number
MIN(timestamp) AS timestamp,
FROM
Queue_Manager
WHERE
priority_number =
(
SELECT
MIN(priority_number)
FROM
Queue_Manager
)
GROUP BY
priority_number
) SQ1 ON
SQ1.priority_number = QM1.priority_number AND
SQ1.timestamp = QM1.timestamp
Keine Methode macht exakte Übereinstimmungen in beiden priority_number und Zeitstempel, also, wenn Sie denken, dass das möglich ist (und vielleicht auch wenn Sie es nicht tun) Sie werden eine oder zwei Zeilen hinzufügen müssen eine weitere Ebene zu gehen, um die Kennung verwendet oder etwas anderes, das Einzigartigkeit garantiert. Oder einfach nur Ihre Frontend schreiben den gelegentlichen Fall von immer wieder zwei Reihen (vielleicht einfach ignorieren die zweite - Sie werden es das nächste Mal durchkommen) zu behandeln.
jede Methode testen und sehen, welche für Sie besser funktioniert.
Auch, wie groß erwarten Sie die Warteschlange zu bekommen? Es könnte sinnvoll sein, nur mit Ihrer Bestellung abzufragen BY und hat nur das vordere Ende die erste Zeile abgerufen werden.
Lesen Sie diese Abschnitt und wählen Sie die Variante, die Sie am meisten gibt geeignete Kompatibilität. Wahrscheinlich ist die Verwendung von Cursor die nur mehr oder weniger universell kompatibel Art und Weise, aber eine gewisse Leistungseinbuße hat, die nicht machen könnte es lohnt sich (Profil!).
Relationale Datenbanken sind nicht groß an Warteschlangen verwalten.
Versuchenbei MSMQ sucht in der Windows-Welt, ActiveMQ in der Java-Welt oder Websphere MQ in der Geschäftswelt.
Diese Produkte machen eine einzige Sache, verwalten Warteschlangen, aber sie tun es auch.