Question

J'implémente une petite file d'attente pour gérer le processus à exécuter en premier. J'utilise une table dans une base de données pour le faire. Voici la structure de la table (je me moque de SQLite):

        "id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL ,
        "identifier" VARCHAR NOT NULL ,
        "priority_number" INTEGER DEFAULT 15,
        "timestamp" DATETIME DEFAULT CURRENT_TIMESTAMP,
        "description" VARCHAR

J'essaie d'écrire SQL pour me donner la ligne du processus qui peut être exécuté ensuite. Voici quelques exemples de données:

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

Si j'utilise ce SQL, je peux obtenir les données dans le bon ordre:

select * from queue_manager order by priority_number, timestamp;

Cela me donnera l'élément avec le numéro de priorité le plus bas (le plus important) en haut, et dans ces numéros de priorité, le plus tôt dans la file d'attente (par horodatage) en haut.

Je pouvais exécuter cette requête et ne prendre que la première ligne, mais je préférerais le faire avec une requête SQL qui me donnerait la ligne du processus qui se trouve en haut de la file d'attente (dans l'exemple de données ci-dessus , la ligne avec id = 7).

J'ai essayé de faire des auto-jointures et des sous-requêtes, mais je dois avoir un blocage mental. Je n'arrive pas à comprendre.

Merci d'avance!

MODIFIER

J'ai oublié de mentionner que je recherche une requête indépendante de la base de données. Je me moque de cela dans SQlite, mais il est fort probable que je vais l'implémenter dans DB2 ou Oracle. J'avais pensé utiliser une "limite 1". tapez l'opérateur sur ma requête, mais c'est différent entre les différents moteurs de base de données.

Était-ce utile?

La solution

Voir si cela fonctionne:

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)

Autres conseils

select * from queue_manager order by priority_number, timestamp LIMIT 1;

Pour ce qui est de ce qu'on appelle "l'indépendance de la base de données", c'est un mythe pour la plupart des tâches du monde réel. En règle générale, vous ne pouvez même pas créer de schéma indépendamment de la base de données.

Si vous voulez que ce soit "sûr en même temps" sur quelque chose comme InnoDB, faites:

1) Ajoutez un champ 'in_progress'.

2) Désactivez AUTOCommit

3) SELECT * FROM queue_manager où in_progress = 0 commande par numéro de priorité, horodatage LIMIT 1 FOR UDPATE;

4) UPDATE queue_manager SET SET in_progress = 1 où id = X;

5) COMMIT

6) Faites le travail. Supprimez ensuite la ligne lorsque vous avez terminé. Avoir un "processus maître" gérer / redéléguer / nettoyer les anciens travaux "in_progress".

La meilleure façon de faire est dépendante de la base de données; c’est beaucoup plus simple d’avoir des processus de récupération différents pour les différents SGBD cibles par rapport à la surcharge de curseurs ou d’autres constructions.

La sélection d’un nombre limité de lignes s’effectue différemment selon les types de code SQL. Par conséquent, il se peut que vous disposiez d’une méthode intégrée pour le faire. Par exemple, dans MS SQL Server:

SELECT TOP 1
     identifier,
     priority_number,
     timestamp,
     description
FROM
     dbo.Queue_Manager
ORDER BY
     priority_number,
     timestamp

Pour ce faire, dans un SQL compatible ANSI, les méthodes suivantes devraient fonctionner:

    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

Ou vous pouvez essayer:

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

Aucune méthode ne prend en compte les correspondances exactes dans BOTH priority_number et timestamp. Par conséquent, si vous pensez que cela est possible (et peut-être même si vous ne le faites pas), vous devrez ajouter une ligne ou deux pour passer à un niveau supérieur en utilisant l'identifiant ou quelque chose d'autre qui garantit l'unicité. Ou bien écrivez simplement votre frontal pour gérer le cas occasionnel de récupérer deux rangées (peut-être simplement ignorer la seconde - vous l'obtiendrez la prochaine fois).

Testez chaque méthode et voyez laquelle vous convient le mieux.

En outre, quelle devrait être la taille de la file d'attente? Il pourrait être raisonnable de simplement interroger avec ORDER BY et de n’avoir que le client récupéré la première ligne.

Lisez la cette section et sélectionnez la variante qui vous donne le plus compatibilité appropriée. L’utilisation de curseurs est sans doute la seule solution compatible de manière plus ou moins universelle, mais présente quelques inconvénients en termes de performances qui pourraient ne pas en valoir la peine (profil!).

Les bases de données relationnelles ne permettent pas de gérer les files d'attente.

Essayez de regarder MSMQ dans le monde Windows, ActiveMQ dans le monde Java ou Websphere MQ dans le monde des affaires.

Ces produits font une seule chose, gèrent les files d'attente, mais ils le font bien.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top