質問

最初に実行するプロセスを処理する小さなキューを実装しています。これを行うためにデータベースのテーブルを使用しています。以下はテーブルの構造です(SQLiteでモックアップしています):

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

SQLを記述して、次に実行できるプロセスの行を取得しようとしています。サンプルデータを次に示します。

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

このSQLを使用すると、データを適切な順序で取得できます。

select * from queue_manager order by priority_number, timestamp;

これにより、一番上の優先度番号が最も低い(最も重要な)アイテムが表示され、それらの優先度番号では、一番上の(タイムスタンプで)キューへの最も早いアイテムが表示されます。

このクエリを実行し、最初の行のみを取得できましたが、キューの一番上にあるプロセスの1行を取得するSQLクエリでこれを実行したいです(上記のデータ例では) 、id = 7の行)。

セルフジョインとサブクエリを実行しようとしましたが、メンタルブロックを持っている必要があります-うまくいかないようです。

事前に感謝します!

編集

データベースに依存しないクエリを探していることを忘れていました。これをSQliteでモックアップしていますが、これをDB2またはOracleで実装する可能性は十分にあります。 <!> quot; limit 1 <!> quot;を使用することを考えていました。クエリで型演算子を使用しますが、データベースエンジンによって異なります。

役に立ちましたか?

解決

これが機能するかどうかを確認します:

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)

他のヒント

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

<!> quot; database independency <!> quot;と呼ばれるものに関しては、ほとんどの現実世界のタスクの神話です。原則として、データベースに依存しない方法でスキーマを作成することもできません。

InnoDBのようなもので「並行安全」にしたい場合:

1)「in_progress」フィールドを追加します。

2)AUTOCommitをオフにする

3)SELECT * FROM queue_managerここで、in_progress = 0、priority_number、timestamp LIMIT 1 for UDPATEの順に並んでいます。

4)UPDATE queue_manager SET in_progress = 1 where id = X;

5)コミット

6)仕事をする。その後、行が満足のいくものになったら行を削除します。 「マスタープロセス」に古い「in_progress」ジョブを処理/再デリゲート/クリーンアップさせます。

これを行う最良の方法は、データベースに依存しています。カーソルやその他の構造のすべてのオーバーヘッドに対して、異なるターゲットDBMSに対して異なる取得プロシージャを使用する方がはるかに簡単です。

限られた数の行の選択は、SQLのフレーバーごとに異なる方法で実行されるため、使用しているものによっては、その方法が組み込まれている場合があります。たとえば、MS SQL Serverの場合:

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

ANSI互換のSQLでこれを行うには、次のメソッドが機能する必要があります。

    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

または試すことができます:

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

どちらの方法も、priority_numberとtimestampの両方で完全に一致することを考慮していないため、それが可能だと思われる場合は(そうでない場合でも)、識別子を使用して1行または2行追加して、一意性を保証する他の何か。または、フロントエンドを記述して、2行を戻すことがある場合に対処します(2番目の行を無視することもできます-次回はそれを取得します)。

各メソッドをテストして、どちらがより適切かを確認します。

また、キューはどれくらいの大きさを期待していますか? ORDER BYでクエリを実行し、フロントエンドに最初の行のみを取得させることは合理的です。

このセクションを読み、最も価値のあるバリアントを選択します適切な互換性。おそらくカーソルの使用は、多かれ少なかれ普遍的に互換性のある唯一の方法ですが、それだけでは価値がないかもしれないパフォーマンスの低下があります(プロファイル!)。

リレーショナルデータベースはキューの管理に向いていません。

Windowsの世界でMSMQ、javaの世界でActiveMQ、またはビジネスの世界でWebsphere MQを見てみてください。

これらの製品は、キューを管理する単一のことを行いますが、それはうまくいきます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top