如何从一组状态中计算总进度状态?

How to calculate total progress status from a group of statuses?

提问人:Zenith 提问时间:3/8/2023 最后编辑:Zenith 更新时间:3/9/2023 访问量:131

问:

我正在尝试检索存储在 sql server 数据库中的多步骤进程的状态。每个步骤都是表中的一条记录。

当客户端想知道该过程的状态时,我想检索所有步骤的状态,并让我的查询返回状态

  • 当所有步骤的状态都为“已排队”时,为“已排队”,
  • 当其中一个步骤的状态为“正在进行”时,为“正在进行”,
  • 当所有步骤的状态都为“已完成”时,为“已完成”。

此查询会是什么样子?

我在 Sql 方面还没有那么有经验,所以我还没有尝试过任何东西,因为我不知道从哪里开始,也无法在 Google 上真正找到类似这个问题的东西。

根据评论进行编辑: 表格如下所示:

Process
- id uniqueidentifier not null pk
- other stuff
Step
- id uniqueidentifier not null pk
- processId uniqueidentifier not null fk with process.id
- status nvarchar(30) not null

因此,步骤的一些示例数据将是:

编号 进程 Id 地位
ED9D1F80-1941-495A-A282-833FDDF41174 6F940376-27B5-4899-8CF0-BEB89877DA46 进行中
2738A403-7AD4-4396-9B5C-C641BC01F96F 6F940376-27B5-4899-8CF0-BEB89877DA46 排队
4e6a0c8e-49e9-4dc6-adbe-a74f27aff36f 6F940376-27B5-4899-8CF0-BEB89877DA46 排队

这应该导致我的查询返回:

进程 Id 地位
6F940376-27B5-4899-8CF0-BEB89877DA46 进行中
sql sql-server t-sql

评论

1赞 Sean Lange 3/8/2023
为了让人们能够提供帮助,我们需要细节。简而言之,我们需要查看表定义、示例数据以及示例数据的所需输出。除非提供该信息,否则这个问题很可能会结束。
0赞 Sean Lange 3/8/2023
如果你有一张地位表,你会帮自己一个大忙。对于初学者来说,它将被规范化,但你也可以使用该表,这样你就可以做一个聚合,这将使这变得非常容易。
0赞 Yitzhak Khabinsky 3/8/2023
在提出问题时,您需要提供一个最小的可重现示例:(1) DDL 和示例数据填充,即 CREATE 表和 INSERT T-SQL 语句。(2) 需要执行的操作,即逻辑和代码尝试在 T-SQL 中实现它。(3) 期望的输出,基于上面 #1 中的示例数据。(4) 您的 SQL Server 版本 (SELECT @@version;)。问题中的所有内容都是文本,没有图像。
0赞 Joel Coehoorn 3/8/2023
如果您混合了排队和已完成,但没有进行中,该怎么办?
0赞 siggemannen 3/8/2023
这回答了你的问题吗?如何在SQL中对一组行进行分类?

答:

1赞 Ian Boyd 3/8/2023 #1

您可以使用以下查询进行检查:

DECLARE @pid int = 7; --whatever the ID of this process is.

SELECT 
   CASE 
   WHEN EXISTS (SELECT 1 FROM ProcessSteps WHERE ProcessID = @pid AND Status = 'in-progress') THEN 'in-progress'
   WHEN NOT EXISTS (SELECT 1 FROM ProcessSteps WHERE ProcessID = @pid AND Status = 'finished') THEN 'queued'
   ELSE 'finished'
   END AS ProcessStatus
FROM ProcessSteps
WHERE ProcessID = @pid

查询首先检查是否有任何步骤是 。如果有,则返回 的状态。接下来是检查所有步骤是否都已完成,如果未返回,则返回 。in-progressin-progressqueuedfinished

评论

0赞 Zenith 3/8/2023
谢谢!这对我有用。我很确定将来会添加更多状态,但我了解语法,所以我可能会解决它。
0赞 Sean Lange 3/8/2023
这当然会起作用,但在较大的桌子上,性能可能会成为一个问题。子查询作为一列将显著影响性能。
2赞 Joel Coehoorn 3/8/2023 #2

这应该有效,并且可能表现得更好:

SELECT processId, status 
FROM (
    select processId, status
       , row_number() over (partition by processid 
                            order by case when status = 'in-progress' then 0
                                          when status = 'queued' then 1 
                                          else 2 end) rn
    from Step
) t
WHERE rn = 1

但是在原始帖子中有一个重要的未回答的问题,即如果只有 和 项目混合在一起,没有列出任何内容,该怎么办。在这个答案中,我偏向于较早的状态。queuedfinishedin-progressqueued

如果将来可以有更多状态值,我可能会这样做:

SELECT processId, status 
FROM (
    select processId, Step.status
       , row_number() over (partition by processid 
                            order by coalesce(map.priority,100)) rn
    from Step
    left join ( values 
      ('in-progress', 0), 
      ('queued', 1), 
      ('finished' 2)
    ) map(status, priority) ON map.status = Step.status
) t
WHERE rn = 1

这将以更简洁的方式列出映射,缩进更少,使其更易于阅读和维护。它还使您可以轻松地转换为状态表。and instead of 是,因此,如果在更新查询之前添加了状态以了解它,则查询不会完全跳过行。LEFT JOINcoalesce()INNER JOIN