SQL Server 分区和运行案例语句

问题描述 投票:0回答:2

我正在尝试获取 **TableB ** 中的最新记录以获得 ID .. 我厌倦了对最高值进行排名,然后使用结果将以下条件应用于 TableA 中名为“状态”的列:

  • 如果 end 为 null 或空白,则 status = 'Currently Running'

  • 如果最新记录来自过去 48 小时,则 status = 'Recently FInished'

  • 如果结束时间超过 48 小时,则 status = 'not run in more than 48hours'

  • else '最近没有活动'

我附上了screenshot of the data.

CREATE TABLE [dbo].[TableA](
    [ID] [varchar](50) NULL,
    [Status] [varchar](50) NULL
) 

CREATE TABLE [dbo].[TableB](
    [SiteId] [varchar](50) NULL,
    [db_addr] [varchar](50) NULL,
    [Start] [datetime] NULL,
    [End] [datetime] NULL,
    [ID] [varchar](50) NULL
) 
GO

INSERT [dbo].[TableA] ([ID], [Status]) VALUES (N'Z1001', N'')
INSERT [dbo].[TableA] ([ID], [Status]) VALUES (N'Z1002', N'')
INSERT [dbo].[TableA] ([ID], [Status]) VALUES (N'Z1003', N'')
INSERT [dbo].[TableA] ([ID], [Status]) VALUES (N'Z3002', N'')

INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'1001', N'E001',   CAST(N'2023-05-01T00:00:00.000' AS DateTime), CAST(N'2023-05-02T00:10:00.000' AS DateTime), N'Z1001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'1001', N'E001', CAST(N'2023-05-02T01:00:00.000' AS DateTime), CAST(N'2023-05-02T01:10:00.000' AS DateTime), N'Z1001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'1001', N'E001', CAST(N'2023-05-03T01:00:00.000' AS DateTime), CAST(N'2023-05-03T01:10:00.000' AS DateTime), N'Z1001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'2001', N'B002',     CAST(N'2023-05-01T00:00:00.000' AS DateTime), CAST(N'2023-05-02T00:10:00.000' AS DateTime), N'Z2001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'2001', N'B002', CAST(N'2023-05-02T01:00:00.000' AS DateTime), CAST(N'2023-05-02T01:10:00.000' AS DateTime), N'Z2001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'3001', N'B005', CAST(N'2023-05-02T01:00:00.000' AS DateTime), NULL, N'Z3001')
INSERT [dbo].[TableB] ([SiteId], [db_addr], [Start], [End], [ID]) VALUES (N'3002', N'C007', CAST(N'2023-05-10T01:00:00.000' AS DateTime), CAST(N'2023-05-10T01:00:00.000' AS DateTime), N'Z3002')

我试着写一个 SQL Partition 语句,然后是 CASE,但都出错了。

WITH cte AS (
  SELECT a.ID, Status,
    ROW_NUMBER() OVER (PARTITION BY b.db_addr, b.ID ORDER BY b.[End] DESC) AS rn,
    MAX(b.[End]) OVER (PARTITION BY b.db_addr, b.ID) AS latest_end
  FROM TableA a
  JOIN TableB b ON a.ID = b.ID
)
UPDATE a
SET Status = CASE
  WHEN cte.latest_end IS NULL OR cte.latest_end = '' THEN 'Currently Discharging'
  WHEN cte.rn = 1 AND cte.latest_end >= DATEADD(hour, -48, GETDATE()) THEN 'Discharged recently'
  ELSE 'Not discharged in more than 48hours'
  END
FROM TableA a
LEFT JOIN cte ON a.ID = cte.ID
WHERE a.ID IS NOT NULL;
sql sql-server sql-update subquery window-functions
2个回答
0
投票

为每个ID检索最近的行,使用window方法

ROW_NUMBER()
,然后使用
case
子句得到预期的结果:

with cte as (
  select a.*, b.[End], ROW_NUMBER() OVER (partition by a.ID order by [End]) as rn
  from TableA a
  inner join TableB b on b.ID = a.ID
)
select ID, case when [End] is null then 'Currently Running'
          when [End] >= DATEADD(day, -2, GETDATE()) then 'Recently FInished'
          when [End] < DATEADD(day, -2, GETDATE()) then 'not run in more than 48hours'
          else 'no recent activity' end as Status
from cte
where rn = 1

这是更新声明:

with cte as (
  select a.*, b.[End], ROW_NUMBER() OVER (partition by a.ID order by [End]) as rn
  from TableA a
  inner join TableB b on b.ID = a.ID
)
UPDATE TableA
set TableA.Status = case when [End] is null then 'Currently Running'
          when [End] >= DATEADD(day, -2, GETDATE()) then 'Recently FInished'
          when [End] < DATEADD(day, -2, GETDATE()) then 'not run in more than 48hours'
          else 'no recent activity' end
from cte c
inner join TableA a on a.ID = c.ID
where rn = 1

结果:

ID      Status
Z1001   not run in more than 48hours
Z1002   not run in more than 48hours
Z3001   Currently Running
Z3002   Recently FInished

这里演示


0
投票

看起来你不需要窗户 在这里发挥作用。您可以从第二个表中获取每个

end
的最新
id
,只需
max
.

我们还可以避免 CTE(您的代码稍后会连接回表),并直接从相关子查询返回新值:

update a
set status = (
    select 
        case
            when max([End]) is null then 'currently running'
            when max([End]) >= dateadd(day, -2, getdate()) then 'recently finished'
            else 'did not run in more than 48 hours'
        end   
    from tableb b
    where b.id = a.id
)
from tablea a
where a.id is not null

备注:

  • case
    的最后一个分支(产生最近没有活动的分支)无法访问;之前的分支,没有在超过 48 小时内运行,将首先匹配
  • 这还会更新第二个表中完全不匹配的行,并将给它们状态没有在超过 48 小时内运行 - 在我看来这与您的问题陈述和尝试一致
© www.soinside.com 2019 - 2024. All rights reserved.