制定查询优先级队列表的 SQL

发布于 2024-07-12 02:05:06 字数 1583 浏览 8 评论 0原文

我正在实现一个小队列来处理哪个进程首先运行。 我正在使用数据库中的表来执行此操作。 这是表的结构(我在 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;

这将为我提供顶部优先级编号最低(最重要)的项目,并且在这些优先级编号中,最早进入的项目顶部的队列(按时间戳)。

我可以运行这个查询,并且只获取第一行,但我宁愿使用 SQL 查询来执行此操作,该查询将为我提供位于队列顶部的进程的一行(在上面的示例数据中,该行id=7)。

我尝试进行自连接和子查询,但我一定有心理障碍 - 我似乎无法做到正确。

提前致谢!

编辑

我忘了提及我正在寻找独立于数据库的查询。 我在 SQlite 中模拟了这一点,但我很有可能在 DB2 或 Oracle 中实现它。 我曾想过在查询中使用“limit 1”类型运算符,但这在不同的数据库引擎之间是不同的。

I am implementing a small queue to handle which process gets to run first. I am using a table in a database to do this. Here is the structure of the table (I'm mocking it up in SQLite):

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

I am trying to write SQL to give me the row of which process can run next. Here is some sample data:

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

If I use this SQL, I can get the data in the proper order:

select * from queue_manager order by priority_number, timestamp;

This will give me the item with the lowest priority number (most important) at the top, and in those priority numbers, the earliest into the queue (by timestamp) at the top.

I could run this query, and only take the first row, but I would rather do this with a SQL query that would give me the one row of the process that is at the top of the queue (in the example data above, the row with id=7).

I tried doing self joins and sub queries, but I must be having a mental block - I just can't seem to get it right.

Thanks in advance!

EDIT

I forgot to mention that I am looking for a database-independent query. I am mocking this up in SQlite, but there is a good possibility I will implement this in DB2 or Oracle. I had thought to use a "limit 1" type operator on my query, but that is different between different database engines.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

_畞蕅 2024-07-19 02:05:06

看看这是否有效:

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)

See if this works:

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)
乙白 2024-07-19 02:05:06
select * from queue_manager order by priority_number, timestamp LIMIT 1;

至于所谓的“数据库独立性”,对于大多数现实世界的任务来说这是一个神话。 通常,您甚至无法以独立于数据库的方式创建模式。

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

As for such called "database independency", it's a myth for most real world tasks. As a rule, you cannot even create schema in database-independent way.

你与昨日 2024-07-19 02:05:06

如果你希望它在 InnoDB 之类的东西上是“并发安全”的,请执行以下操作:

1)添加一个“in_progress”字段。

2) 关闭 AUTOCommit

3) SELECT * FROM queue_manager where in_progress = 0 order bypriority_number, timestamp LIMIT 1 FOR UDPATE;

4)更新queue_manager SET in_progress = 1,其中id = X;

5) 承诺

6) 完成工作。 然后在完成满意后删除该行。 有一个“主进程”处理/重新委托/清理旧的“进行中”作业。

If you want it to be 'concurrent safe' on something like InnoDB do:

1) Add an 'in_progress' field.

2) Turn off AUTOCommit

3) SELECT * FROM queue_manager where in_progress = 0 order by priority_number, timestamp LIMIT 1 FOR UDPATE;

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

5) COMMIT

6) Do the job. Then delete the row when its done to satisfaction. Have a 'master process' handle/redelegate/clean up old 'in_progress' jobs.

薄情伤 2024-07-19 02:05:06

做到这一点的最佳方法是依赖于数据库; 与游标或其他结构的所有开销相比,为不同的目标 DBMS 使用不同的检索过程要简单得多。

The best way to do this is database dependent; it's a much simpler thing to have different retrieval procs for the different target DBMSs versus all of the overhead of cursors or other constructs.

紫竹語嫣☆ 2024-07-19 02:05:06

在不同类型的 SQL 中,选择有限数量的行的方式有所不同,因此根据您使用的 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 和时间戳中的精确匹配,因此,如果您认为这是可能的(甚至可能您不需要)您需要添加一两行以使用标识符或其他保证唯一性的内容进入一个更高的级别。 或者只是编写前端来处理偶尔返回两行的情况(也许只是忽略第二行 - 下次你会得到它)。

测试每种方法,看看哪种方法更适合您。

另外,您预计队列有多大? 仅使用 ORDER BY 进行查询并且仅让前端检索第一行可能是合理的。

Selecting a limited number of rows is done differently in different flavors of SQL, so depending on which you are using there might be a built in way to do it. For example, in MS SQL Server:

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

To do this in ANSI compatible SQL, the following methods should work:

    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

Or you can try:

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

Neither method accounts for exact matches in BOTH priority_number and timestamp, so if you think that's possible (and maybe even if you don't) you'll need to add a line or two to go one more level using the identifier or something else that guarantees uniqueness. Or just write your front end to handle the occasional case of getting back two rows (maybe just ignore the second - you'll get it the next time through).

Test each method and see which works better for you.

Also, how large do you expect the queue to get? It could be reasonable to just query with your ORDER BY and only have the front end retrieve the first row.

温暖的光 2024-07-19 02:05:06

阅读部分并选择为您提供最合适兼容性的变体。 游标的使用可能是唯一或多或少普遍兼容的方式,但会带来一些性能损失,可能不值得(配置文件!)。

Read this section and select the variant that gives you the most suitable compatibility. Probably the use of cursors is the only more or less universally compatible way, but has some performance penalty that might not make it worth it (profile!).

此生挚爱伱 2024-07-19 02:05:06

关系数据库不擅长管理队列。

尝试查看 Windows 世界中的 MSMQ、Java 世界中的 ActiveMQ 或商业世界中的 Websphere MQ。

这些产品只做一件事情,管理队列,但它们做得很好。

Relational databases are not great at managing queues.

Try looking at MSMQ in the windows world, ActiveMQ in the java world or Websphere MQ in the business world.

These products do a single thing, manage queues, but they do it well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文