Обновление таблицы без использования курсора и даты - PullRequest
4 голосов
/ 01 января 2011

Пожалуйста, скопируйте и запустите следующий скрипт

DECLARE @Customers TABLE (CustomerId INT)
DECLARE @Orders TABLE ( OrderId INT, CustomerId INT, OrderDate DATETIME )
DECLARE @Calls TABLE (CallId INT, CallTime DATETIME, CallToId INT, OrderId INT)
-----------------------------------------------------------------
INSERT INTO @Customers SELECT 1
INSERT INTO @Customers SELECT 2
INSERT INTO @Customers SELECT 3
-----------------------------------------------------------------
INSERT INTO @Orders SELECT 10, 1, DATEADD(d, -20, GETDATE())
INSERT INTO @Orders SELECT 11, 1, DATEADD(d, -10, GETDATE())
INSERT INTO @Orders SELECT 12, 2, DATEADD(d, -8, GETDATE())
INSERT INTO @Orders SELECT 13, 2, DATEADD(d, -6, GETDATE())
INSERT INTO @Orders SELECT 14, 3, DATEADD(d, -4, GETDATE())
-----------------------------------------------------------------
INSERT INTO @Calls SELECT 101, DATEADD(d, -19, GETDATE()), 1, NULL
INSERT INTO @Calls SELECT 102, DATEADD(d, -17, GETDATE()), 1, NULL
INSERT INTO @Calls SELECT 103, DATEADD(d, -9, GETDATE()), 1, NULL
INSERT INTO @Calls SELECT 104, DATEADD(d, -6, GETDATE()), 1, NULL
INSERT INTO @Calls SELECT 105, DATEADD(d, -5, GETDATE()), 1, NULL
INSERT INTO @Calls SELECT 106, DATEADD(d, -4, GETDATE()), 2, NULL
INSERT INTO @Calls SELECT 107, DATEADD(d, -2, GETDATE()), 2, NULL
INSERT INTO @Calls SELECT 108, DATEADD(d, -2, GETDATE()), 3, NULL

Я хочу обновить таблицу @Calls и мне нужны следующие результаты.

alt text

Я использую следующеезапрос (Старый запрос перед ответом)

UPDATE  @Calls
SET     OrderId = ( 
                    CASE 
                        WHEN (s.CallTime > e.OrderDate)
                          THEN e.OrderId
                    END                                 
                )
FROM    @Calls s INNER JOIN @Orders e   ON s.CallToId = e.CustomerId

Редактировать: Сейчас я использую этот запрос

UPDATE c set OrderID = o1.OrderID
from @Calls c inner join @Orders o1 on c.CallTime > o1.OrderDate  
    left join @Orders o2 on c.CallTime > o2.OrderDate 
            and o2.OrderDate > o1.OrderDate 
where o2.OrderID is null
and o1.CustomerId = c.CallToId

и результат моего запроса не тот, который мне нужен.

Требование: Как видите, есть два заказа.Один на 2010-12-12, а другой на 2010-12-22.Я хочу обновить @Calls таблицу с соответствующим OrderId относительно CallTime.

Короче говоря, если последующие Заказы добавлены, и есть дальнейшие вызовы, то мы предполагаем, что новый вызов связан с большинствомнедавний заказ

Примечание: Это примерные данные, поэтому у меня всегда два заказа.Там может быть более 10 заказов и более 100 вызовов и 1000 клиентов.

Примечание2 Не удалось найти хорошее название для этого вопроса.Пожалуйста, измените его, если вы считаете, что лучше.

Edit2: Запрос, представленный в ответе, занимает слишком много времени.Общее количество записей для обновления составляет около 250000.

Спасибо.

1 Ответ

5 голосов
/ 01 января 2011

Вы можете использовать левое соединение, чтобы проверить наличие «нежелательных» строк и устранить их в своем предложении WHERE:

UPDATE c set OrderID = o1.OrderID
from @Calls c
    inner join
        @Orders o1
            on
                c.CallTime > o1.OrderDate
            left join
        @Orders o2
            on
                c.CallTime > o2.OrderDate and
                o2.OrderDate > o1.OrderDate
where
    o2.OrderID is null

select * from @Calls

т.е. Вы сначала настраиваете свой запрос, используя обычные объединения - вы хотите найти строку в порядках (o1), которая происходит перед вызовом (c). Но это может вернуть несколько строк (если перед вызовом (c) встречается более одной строки). Таким образом, вы выполняете другое соединение с ордерами (o2), ища строки, которые происходят после строки, найденной в (o1), но все же перед вызовом (c). Если мы можем сделать такое совпадение, то мы не хотим, чтобы эта (o1) строка все-таки. Поэтому мы фильтруем эту объединенную строку в предложении WHERE.


Теперь, когда вы добавили CustomerID, вы должны учитывать, что и в ваших условиях соединения - это левое соединение с @Orders (o2) найдет любой более поздний вызов, а не только один для того же клиента. Чтобы сохранить симметрию между двумя соединениями с заказами:

UPDATE c set OrderID = o1.OrderID
from @Calls c
    inner join
        @Orders o1
            on
                c.CallTime > o1.OrderDate
                            and c.CallToID = o1.CustomerId /* <-- New line 1 */
            left join
        @Orders o2
            on
                c.CallTime > o2.OrderDate and
                o2.OrderDate > o1.OrderDate
                            and c.CallToID = o2.CustomerId /* <-- New line 2 */
where
    o2.OrderID is null

Надеемся, что это поможет решить некоторые проблемы с производительностью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...