【问题标题】:sql case when newValue else previousValuesql case when newValue else previousValue
【发布时间】:2015-11-02 12:31:56
【问题描述】:

我正在尝试从 Select 创建一个更新,在特定情况下 (88) 应该使用以前的值来更新列字段

UPDATE myTable
SET MyDateCol = CASE MYSelect.Indicator 
                WHEN 88 THEN @previosValue 
                ELSE MYSelect.NewValue
FROM  myTable
INNER JOIN    (    ...    ) AS MYSelect

ON myTable.ID = MYSelect.ID

示例:

MYSelect             | myTable
                     |
Indicator NewValue   | MyDateCol 
   0         1       |    1
   1         2       |    2
   88        3       |    2 <-
   3         4       |    4
   4         5       |    5
   5         6       |    6
   6         7       |    7
   88        8       |    7 <-

全面更新

UPDATE [dbo].[BestellDetails]
   SET [Datum] = CASE MYTABLE.WochenTag WHEN 88  THEN lag(MyDate) over(order by MYTABLE.MyDate)  ELSE MyDate END
FROM  [BestellDetails]
INNER JOIN
(
    SELECT INNERTabelle.BestellDetailId,INNERTabelle.WochenTag, DATEADD (dd,INNERTabelle.WochenTag, INNERTabelle.NewDatum) AS MyDate
    FROM
    (
        SELECT TOP 100 PERCENT BestellDetailId, 
                    dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, 
                    dbo.Bestellung.Kalenderwoche) AS NewDatum,
                    (CASE BestellDetails.RefMenuId WHEN Speiseplandetails.RefMoId THEN 0 
                                                   WHEN Speiseplandetails.RefDiId THEN 1 
                                                   WHEN Speiseplandetails.RefMiId THEN 2 
                                                   WHEN Speiseplandetails.RefDoId THEN 3 
                                                   WHEN Speiseplandetails.RefFrId THEN 4 
                                                   WHEN Speiseplandetails.RefSaId THEN 5 
                                                   WHEN Speiseplandetails.RefSoId THEN 6 ELSE 88 END) AS WochenTag
        FROM            dbo.Speiseplandetails 
        RIGHT OUTER JOIN dbo.BestellDetails ON dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefMoId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefDiId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefMiId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefDoId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefFrId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefSaId 
        OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefSoId 

        RIGHT OUTER JOIN dbo.Bestellung ON dbo.BestellDetails.RefBestellId = dbo.Bestellung.BestellId

        order by BestellDetailId

    ) as INNERTabelle
) AS MYTABLE

ON [BestellDetails].BestellDetailId = MYTABLE.BestellDetailId

【问题讨论】:

  • 如果是sql server或者oracle,可以看lag()函数。
  • 定义“以前的”。是否基于对NewValue 列中的值进行排序?
  • @Damien_The_Unbeliever 是的,确实
  • 我们可以连续两行都有88 指示符吗?
  • @Damien_The_Unbeliever 为什么我们需要 2 个指标行是不够的?并确保您可以根据需要再创建 1 行

标签: sql sql-server select sql-update case


【解决方案1】:
UPDATE myTable
SET MyDateCol = CASE MYSelect.Indicator 
                WHEN 88 THEN (select lag(newvalue) over(order by newvalue) from MySelect) -- @previosValue 
                ELSE MYSelect.NewValue
FROM  myTable
INNER JOIN    (    ...    ) AS MYSelect
ON myTable.ID = MYSelect.ID

这是假设必须根据newvalue 列中的升序选择先前的值。

【讨论】:

  • Windowed functions can only appear in the SELECT or ORDER BY clauses. 它可能与我的DATEADD 有关系
  • 我试过你的修改,现在在Select ... over ... 部分找不到MySelect
【解决方案2】:

请尝试以下查询。 它优化了您的查询,还处理了重复 88 值的情况。就我而言,我使用了NULL 而不是88

我们可以连续两行都有一个 88 指示符吗? – Damien_The_Unbeliever

CREATE TABLE #temp(
BestellDetailId int, row_num int,MyDate date
)

INSERT INTO #temp
SELECT TOP 100 PERCENT 
    BestellDetailId,
    ROW_NUMBER() OVER (order by BestellDetailId) as row_num,        
    (
    CASE BestellDetails.RefMenuId 
                               WHEN Speiseplandetails.RefMoId THEN DATEADD (dd,0, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefDiId THEN DATEADD (dd,1, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefMiId THEN DATEADD (dd,2, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefDoId THEN DATEADD (dd,3, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefFrId THEN DATEADD (dd,4, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefSaId THEN DATEADD (dd,5, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               WHEN Speiseplandetails.RefSoId THEN DATEADD (dd,6, dbo.FirstDateOfWeekISO8601(dbo.Bestellung.Jahr, dbo.Bestellung.Kalenderwoche) )
                               ELSE NULL END
    ) AS MyDate

FROM  dbo.Speiseplandetails 
    RIGHT OUTER JOIN dbo.BestellDetails ON dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefMoId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefDiId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefMiId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefDoId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefFrId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefSaId 
                OR dbo.BestellDetails.RefMenuId = dbo.Speiseplandetails.RefSoId 
    RIGHT OUTER JOIN dbo.Bestellung ON dbo.BestellDetails.RefBestellId = dbo.Bestellung.BestellId
order by BestellDetailId

--updating the temp table with correct values
update t1
set t1.myDate=t3.myDate
from #temp t1 left join #temp t3 
on t3.row_num in 
(select max(row_num) from #temp t2 where t2.myDate is not null and t2.row_num<t1.row_num)
where t1.MyDate is NULL

UPDATE [dbo].[BestellDetails]
   SET [Datum] = MYTABLE.myDate
FROM  [BestellDetails]

INNER JOIN
#temp AS MYTABLE
ON [BestellDetails].BestellDetailId = MYTABLE.BestellDetailId

下面是使用最后一个值更新表的示例小提琴 http://sqlfiddle.com/#!6/c78ae/8

【讨论】:

  • 在我的本地数据库上执行时间为 1:15:57 :D,但它可以满足我的要求,并且只会运行一次
【解决方案3】:

lag() 应该做你想做的事。可以直接放在MySelect定义中。或者使用子查询:

WITH myselect as (
      . . .
     )
UPDATE myTable
    SET MyDateCol = (CASE MYSelect.Indicator 
                        WHEN 88 THEN MYSelecct.prevvalue 
                        ELSE MYSelect.NewValue
                     END
FROM  myTable INNER JOIN
      (SELECT myselect.*, lag(newvalue) over (order by newvalue) as prevvalue
       FROM myselect
      ) myselect
      ON myTable.ID = MYSelect.ID;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 2019-02-01
    • 1970-01-01
    • 2020-09-22
    相关资源
    最近更新 更多