在 SQL SERVER 中使用交叉应用进行更新

Posted

技术标签:

【中文标题】在 SQL SERVER 中使用交叉应用进行更新【英文标题】:Update with cross apply in SQL SERVER 【发布时间】:2017-03-21 13:10:04 【问题描述】:

我在#def 中有这样的表格:

#def table 我只想计算当前期间“201702”的每个服务订单之间的天数。 Reservice = 0 表示之前未进行过维修。每次再服务时,再服务的计数都会增加。

select 
s1.period,
,s1.company
,s1.prod
,s1.id1
,S1.id2
,s1.serv_date
,t.last_servdate
,datediff(dd, ISNULL(T.last_servdate, s1.[serv_Date]),s1.serv_date)AS [Days       Since last] from #def s1 
Outer apply(
select 
top 1 serv_date as last_servdate from #def s2
where s1.prod=s2.prod and s1.id1 =s2.id1
and s1.id2=s2.id2 and s1.company =s2.company
and s2.reservice = s1.reservice-1 and s1.company =’abc’
and s2.company =’abc’)T 
where s1.company_code =’abc’ and s1.period ='201702'

  update s1 
  set days_btwn_service = datediff(dd, ISNULL(T.last_servdate,s1.serv_Date]),s1.serv_date) from #def s1 
  Outer apply(
  select top 1 serv_date as last_servdate from #def s2
  where s1.prod=s2.prod 
  and s1.id1 =s2.id1
  and s1.id2=s2.id2 
  and s1.company =s2.company
  and s2.reservice = s1.reservice-1 
  and s1.company =’abc’
  and s2.company =’abc’
  )T  where s1.company_code =’abc’ and s1.period ='201702'

上面的SELECT 查询给了我想要的结果。奇怪的是,在同一个查询中使用 UPDATE 语句根本不会给出想要的结果,但只有很少的行被更新了值。我不知道为什么?!

def 包含已服务多次的所有订单的列表。

编辑:根据@sqlzim 的回复,我更改了查询。他的回复也给出了同样的答案。

【问题讨论】:

左对齐 SQL...很难阅读... 请添加一些示例表数据和预期结果 - 以及格式化文本。同时向我们展示您当前的查询尝试 【参考方案1】:

这看起来像 sql-server,所以这个答案是针对 sql-server 的。

我不明白为什么您会从这些查询中得到两个不同的结果,但如果您使用 select 语句得到正确的结果,您可以使用 @987654325 将其放入 common table expression 和 update @。

serv_date 可以为空吗?如果不是,那么T.serv_date 不能为空,除非您使用outer apply() 而不是cross apply()

;with cte as (
select 
    s1.ord_id
  , s1.period
  , s1.company
  , s1.prod
  , s1.id1
  , S1.id2
  , s1.serv_date
  , s1.days_btwn_service
  , t.last_servdate
  , datediff(day,isnull(T.last_servdate,s1.[serv_Date]),s1.serv_date) as [Days_Since_Last]
from #def s1
  cross apply ( 
    select top 1 serv_date as last_servdate
    from #def s2
    where s1.prod = s2.prod
      and s1.id1 = s2.id1
      and s1.id2 = s2.id2
      and s1.company = s2.company
      and s2.reservice = s1.reservice - 1
    ) T
where s1.company_code = 'abc'
 and s1.period = '201702'
)
--select * from cte;
update cte 
  set days_btwn_service = [Days_Since_Last];
  /* This will update the underlying table #def */

/* -- Alternate version
update d 
  set d.days_btwn_service = cte.[Days_Since_Last] 
  from #def d join cte on cte.ord_id=d.ord_id
--*/

检查select的结果,如果正确,运行update而不是select

【讨论】:

@JohnCappelletti 主要来自记事本++中的“Poor Man's T-Sql Formatter” 你有一个错字,它是notepad++ ;) -- 无论如何在 Windows 上。 @SqlZim,CTE!是的!谢谢你。 CTE 更新是否会级联到临时表?选择工作得非常好。更新仍然是个问题。 @JohnCappelletti 我同意我应该更好地格式化它。我不擅长格式化,但我想学习。 SqlZim 的代码可读性很好。下次我会处理的。 :) @SqlZim 还有一个字段 order_id 可以根据 cte 结果唯一标识要更新的行。像这样的东西,但这不起作用 - update d set d.days_btwn_service = [Days since last] from #def d join cte on cte.ord_id=d.ord_id

以上是关于在 SQL SERVER 中使用交叉应用进行更新的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 交叉应用

如何在 SQL Server 的交叉应用联接中指定列名

SQL Server 交叉应用性能问题

SQL Server - where + TVF/SVF、交叉应用、T-SQL

如何使用交叉应用字符串拆分结果更新sql中的表?

SQL Server 交叉应用不起作用?