简体   繁体   中英

Update table without using cursor and on date

Please copy and run following script

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

I want to update @Calls table and need following results.

替代文字

I am using the following query (Old query before answer)

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

Edit: Now I am using this query

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

and the result of my query is not what I need.

Requirement: As you can see there are two orders. One is on 2010-12-12 and one is on 2010-12-22 . I want to update @Calls table with relevant OrderId with respect to CallTime.

In short If subsequent Orders are added, and there are further calls then we assume that a new call is associated with the most recent Order

Note: This is sample data so this is not the case that I always have two Orders. There might be 10+ Orders and 100+ calls and 1000s of Customers.

Note2 I could not find good title for this question. Please change it if you think of any better.

Edit2: The query provided in answer is taking too much time. Total number of records to update is around 250000.

Thanks.

You can use a left join to check for "undesirable" rows, and eliminate them in your WHERE clause:

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

Ie you first set up your query using normal joins - you want to find the row in orders (o1) which occurs before the call (c). But this can return multiple rows (if more than one occurs before the call (c). So you perform another join to orders (o2) seeking rows which occur after the row found in (o1), but still before the call (c). If we can make such a match, then we didn't want that (o1) row after all. So we filter that combined row out in the WHERE clause.


Now that you've added CustomerID, you need to consider that in your join conditions also - that left join to @Orders (o2) is going to find any later call, not just one for the same customer. To keep the symmetry between the two joins to orders:

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

This will also hopefully address some of the performance difficulties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM