【问题标题】:how to update multiple rows using list stored in table variables in SQL如何使用存储在 SQL 表变量中的列表更新多行
【发布时间】:2018-12-05 07:11:38
【问题描述】:

我目前正在尝试实现一些代码,它将获取给定 160 行行列表的日期,并将它们更新为同一个表中另一个日期后一分钟。

所以例如从这些将来自:

> 1058841   2018-06-20 14:15:04.000 Copy of NtO produced
> 1058841   2018-06-14 19:58:03.000 NTO service date set to 24/05/2018

> 969565    2018-06-20 14:15:01.000 17530   Copy of NtO produced
> 969565    2018-06-14 19:58:03.000 148 NTO service date set to 24/05/2018

到这里:

> 1058841   2018-06-14 19:59:03.000 Copy of NtO produced
> 1058841   2018-06-14 19:58:03.000 NTO service date set to 24/05/2018

> 969565    2018-06-14 19:59:03.000 17530   Copy of NtO produced
> 969565    2018-06-14 19:58:03.000 148 NTO service date set to 24/05/2018

我目前的代码如下:

declare @thisdate table
(
thisdate datetime,
thisref nvarchar(50)
)

declare @thisdate2 table
(
thisdate2 datetime
)


insert into @thisdate(thisdate) (select te_date from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_date from ticket_events where te_system_ref in 
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event = 'Copy of NtO produced' and te_system_ref = 969565
) t where rownumber = 1)
;

insert into @thisdate(thisref) select te_system_ref from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_system_ref from ticket_events where te_system_ref in 
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event = 'Copy of NtO produced' and te_system_ref = 969565
) t where rownumber = 1
;

insert into @thisdate2(thisdate2) select te_date from (
select row_number() over (partition by te_system_ref order by (select 0)) as rownumber, te_date from ticket_events where te_system_ref in 
(select sl_system_ref from statutory_letter where sl_letter_batch = 9429)and te_event like 'NTO service date set to%' and te_system_ref = 969565
) t where rownumber = 1
;


update ticket_events
set te_date = dateadd(minute,1,(select thisdate2 from @thisdate2))
where te_date in (select thisdate from @thisdate) and te_system_ref in (select thisref from @thisdate) and te_event = 'Copy of NtO produced'

但是,这样做的问题是,如果用于填充变量的选择查询产生了多个结果,则它不再起作用。我将如何解决这个问题?

还有一个小问题,如何使用行号取最后一行而不是第一行?

任何帮助都将不胜感激!

【问题讨论】:

  • 回答你的“奖金问题”;如果您的ROW_NUMBER() 语句中有一个确定性的ORDER BY 子句,那么您可以通过简单地添加DESC 将其从第一行交换到最后一行。现在最后一行被编号为 #1 而不是第一行。
  • 感谢您的回复!但我很抱歉,我不太确定你所说的确定性 order by 子句是什么意思。我将如何实施?
  • 如果您按日期之类的东西订购,那么它将具有已定义(确定性)的顺序,但按SELECT 0 订购并不适用“真实”顺序。
  • 谢谢!我现在开始工作了

标签: sql tsql variables sql-update row-number


【解决方案1】:

我可能没有完全遵循您在此处尝试实现的目标,但我认为基本问题是您没有参考您尝试完全更新的内容。因此,当您回去进行更新时,您不确定应该更新什么?

我不明白为什么你甚至使用表变量,我认为这可以通过一个查询来实现?

我的第一次尝试是这样的:

WITH Updates AS (
    SELECT
        sl.sl_letter_batch, --not really sure how important this is, but it probably needs joining into the final query
        te.te_system_ref,
        MAX(CASE WHEN te.te_event = 'Copy of NtO produced' THEN te_date END) AS original_date,
        MAX(CASE WHEN te.te_event LIKE 'NTO service date set to%' THEN DATEADD(MINUTE, 1, te_date) END) AS new_date
    FROM
        ticket_events te
        INNER JOIN statutory_letter sl ON sl.sl_system_ref = te.te_system_ref
    GROUP BY
        sl.sl_letter_batch,
        te.te_system_ref)
UPDATE
    te
SET
    te_date = new_date
FROM
    ticket_events te
    INNER JOIN Updates u ON u.te_system_ref = te.te_system_ref AND u.original_date = te.te_date
WHERE
    te.te_event = 'Copy of NtO produced';

...但是没有测试数据,这实际上只是盲目地编写查询。

【讨论】:

  • 嗨,理查德,感谢您的回复!我目前正在尝试实施您的方法。它似乎没有错误,但是我对运行它有点谨慎,因为它似乎不喜欢被事务条款包围。说明第 3 行的错误“关键字'AS' 附近的语法不正确”。还要回答您的评论,“从 sl_letter_batch = 9429 的法定字母中选择 sl_system_ref”是为我提供了在需要更新的ticket_event表
  • 酷,您可能需要小心WITH 语句附近的分号。这可能是您的语法错误的基础?
【解决方案2】:

您使用row_number 走在正确的道路上,但您的实现有点偏离。

要从初始 te_date 获得一分钟增量,您需要初始 te_date 值和每个附加行的增量数字。这可以通过row_number 函数提供,如下所示:

declare @t table(te_system_ref int,te_date datetime, te_event varchar(100));
insert into @t values
 (1058841,'2018-06-20 14:15:04.000','Copy of NtO produced')
,(1058841,'2018-06-14 19:58:03.000','NTO service date set to 24/05/2018')
,(969565, '2018-06-20 14:15:01.000','17530   Copy of NtO produced')
,(969565, '2018-06-14 19:58:03.000','148 NTO service date set to 24/05/2018')
;

with d as
(
    select te_system_ref
            ,te_date
            ,te_event    -- row_number gets your minute increments
            ,row_number() over (partition by te_system_ref order by te_date) - 1 as rn
    from @t
)
select te_system_ref    -- min() over function gets the earliest date within the te_system_ref group, which we can add the incremental minutes to.
        ,dateadd(minute,rn,min(te_date) over (partition by te_system_ref)) as te_date
        ,te_event
from d
order by te_system_ref
        ,te_date;

输出:

+---------------+-------------------------+----------------------------------------+
| te_system_ref |         te_date         |                te_event                |
+---------------+-------------------------+----------------------------------------+
|        969565 | 2018-06-14 19:58:03.000 | 148 NTO service date set to 24/05/2018 |
|        969565 | 2018-06-14 19:59:03.000 | 17530   Copy of NtO produced           |
|       1058841 | 2018-06-14 19:58:03.000 | NTO service date set to 24/05/2018     |
|       1058841 | 2018-06-14 19:59:03.000 | Copy of NtO produced                   |
+---------------+-------------------------+----------------------------------------+

【讨论】:

    猜你喜欢
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多