Нужна помощь в оптимизации заявления об обновлении

У меня есть две таблицы:

create table CurrentDay (
ID int identity primary key,
ssn varchar(10), 
val money, 
CheckDate datetime, 
CurrentStatus tinyint)

create table PreviousDay (
ID int identity primary key,
ssn varchar(10), 
val money, 
CheckDate datetime, 
CurrentStatus tinyint)

Мне нужно обновить поле CurrentDay.CurrentStatus со следующими значениями:

  • 111, если в PreviousDay.ssn тот же ssn, что и в CurrentDay, и если значение PreviousDay такое же, как и в CurrentDay;
  • 112, если в PreviousDay.ssn такое же, как в CurrentDay, и если значение PreviousDay больше, чем в CurrentDay;
  • 113, если в PreviousDay.ssn такое же, как в CurrentDay, и если значение PreviousDay меньше, чем в CurrentDay;
  • 114,если в нем нет PreviousDay.ssn такой же как и в CurrentDay т.е. ssn только в CurrentDay (это сегодняшняя информация) .

Я бы написал какой-то запрос, но желательно найти другой способ выполнения этой задачи, используя только одно соединение между таблицами PreviousDay и CurrentDay. Очевидно, что это не очень удачный вид... Вот мой вариант:

Update CurrentDay 
Set CurrentStatus=case
when exists (select PreviousDay.ID from PreviousDay 
where PreviousDay.ssn=CurrentDay.ssn AND 
PreviousDay.val=CurrentDay.val  AND
PreviousDay.CheckDate=DATEADD(day,-1,CurrentDay.CheckDate))
then 111
when exists (select PreviousDay.ID from PreviousDay 
where PreviousDay.ssn=CurrentDay.ssn AND 
PreviousDay.val>CurrentDay.val  AND
PreviousDay.CheckDate=DATEADD(day,-1,CurrentDay.CheckDate))
then 112
when exists (select PreviousDay.ID from PreviousDay 
where PreviousDay.ssn=CurrentDay.ssn AND 
PreviousDay.val<CurrentDay.val  AND
PreviousDay.CheckDate=DATEADD(day,-1,CurrentDay.CheckDate))
then 113
when exists (select PreviousDay.ID from PreviousDay 
where PreviousDay.ssn!=CurrentDay.ssn AND 
PreviousDay.CheckDate=DATEADD(day,-1,CurrentDay.CheckDate))
then 114
end;

Вот другой запрос, но в этом случае я не могу обновить fieid CurrentDay.CurrentStatus со значением 114, потому что в обеих таблицах есть только совпадающие строки на ssn:

Set Currentday.CurrentStatus=(select 111 where PreviousDay.val=CurrentDay.val union all select 112 where and PreviousDay.val>CurrentDay.val union all select 113 where and PreviousDay.val<CurrentDay.val /*union all select 114 */ ) from PreviousDay join CurrentDay on PreviousDay.ssn=CurrentDay.ssn and PreviousDay.CheckDate=DATEADD(day,-1,CurrentDay.CheckDate)

У тебя есть другие идеи?


person Balend    schedule 27.12.2009    source источник


Ответы (2)


Что-то вроде:

UPDATE
    C
Set
    CurrentStatus = CASE
            WHEN P.val = C.val THEN 111
            WHEN P.val > C.val THEN 112
            WHEN P.val < C.val THEN 113
            ELSE 114 ---this works because if P.VAL is null, that is no matching row
        END
FROM
    CurrentDay C
    LEFT JOIN
    PreviousDay P On C.ssn = P.ssn AND P.CheckDate = DATEADD(day, -1, C.CheckDate))
person gbn    schedule 27.12.2009
comment
Я бы порекомендовал явно указать 114. Статус 114 означает, что SSN не существовало накануне, поэтому он должен указывать, КОГДА P.val IS NULL; Это лучше для тех, кто позже читает код. - person Chris Shaffer; 27.12.2009

Вы можете попробовать что-то вроде этого

UPDATE CurrentDay 
        SET CurrentStatus =
        CASE 
            WHEN cd.val = pd.val THEN 111
            WHEN cd.val < pd.val THEN 112
            WHEN cd.val > pd.val THEN 113
            WHEN pd.val IS NULL THEN 114
        END
FROM    CurrentDay cd LEFT JOIN
        PreviousDay pd ON   cd.ssn = pd.ssn
                        AND cd.CheckDate = DATEADD(d, 1, pd.CheckDate)

Это был мой тестовый код. Поэкспериментируйте с записями val для PreviousDay, чтобы проверить, работает ли это, или полностью удалите запись для PreviousDay, чтобы увидеть новую опцию Entry.

DECLARE  @CurrentDay table (
ID int identity primary key,
ssn varchar(10), 
val money, 
CheckDate datetime, 
CurrentStatus tinyint)



DECLARE @PreviousDay table (
ID int identity primary key,
ssn varchar(10), 
val money, 
CheckDate datetime, 
CurrentStatus tinyint)

INSERT INTO @CurrentDay (ssn, val, CheckDate)  SELECT 1, 1, '02 Jan 2009'
INSERT INTO @PreviousDay (ssn, val, CheckDate)  SELECT 1, 0, '01 Jan 2009'

UPDATE @CurrentDay 
        SET CurrentStatus =
        CASE 
            WHEN cd.val = pd.val THEN 111
            WHEN cd.val < pd.val THEN 112
            WHEN cd.val > pd.val THEN 113
            WHEN pd.val IS NULL THEN 114
        END
FROM    @CurrentDay cd LEFT JOIN
        @PreviousDay pd ON  cd.ssn = pd.ssn
                        AND cd.CheckDate = DATEADD(d, 1, pd.CheckDate)

SELECT * FROM @CurrentDay
person Adriaan Stander    schedule 27.12.2009
comment
Тот же комментарий, что и для gbn - должен быть явным для кода 114 (включая проверку NULL). Я мог бы поклясться, что у вас была проверка NULL, когда я проголосовал, теперь это не так. - person Chris Shaffer; 27.12.2009
comment
Менял, что-то в этом роде? - person Adriaan Stander; 27.12.2009
comment
Он будет работать правильно в любом случае, просто самодокументируясь с проверкой NULL. - person Chris Shaffer; 27.12.2009