使用旧记录中的数据更新最新记录

时间:2017-01-12 13:52:43

标签: sql-server tsql

我有一张报纸订阅者的表格:

Subscribers:
==============
ID INT,
Status,
Address,
IndexAddress,
StartDate,
EndDate,
SubscriberID,
PaperID

IndexAddress是对我的内部地址表的引用,我保持"正确"地址(你不会相信有多少人不知道他们住在哪里)。地址是客户提供的地址。

每次订阅者结束订阅时,我都会保存数据,当他续订订阅时,我想从我的表中的旧子订单行重新获取旧的IndexAddress。

数据库中的数据如下所示:

1   1   MyLocalAddress  13455   20160101    20160501    100     5
8   1   MyLocalAddress  13455   20160820    20161201    100     5
14  1   MyLocalAddress  13455   20161228    20170107    100     5
18  0   MyLocalAddress  NULL    20170109    NULL        100     5

ID 1,状态1,本地地址,指向我内部系统中的地址13455,启动160101,结束160501,客户编号为100,纸号为5。

最后一行,ID 18刚刚到达数据库,我想确保自动找到IndexAddress号码所以我不必手动匹配它,但我也想绝对确定我从ID为14的行中获取信息,因为数据库中的旧信息可能是错误的(在这种情况下它不是,但它可能)。

这是我修复此问题的SQL:

UPDATE s SET
    Status = s2.Status,
    IndexAddress = s2.IndexAddress
FROM dbo.Subscribers s
JOIN dbo.Subscribers s2 ON s2.SubscriberID = s.SubscriberID
WHERE 1 = 1
    AND s.Status <> s2.Status
    AND s2.Status = 1
    AND s2.ID IN
    (
        SELECT
            MAX(s3.ID)
        FROM dbo.Subscribers s3
        WHERE 1 = 1
            AND s3.SubscriberID = s.SubscriberID
            AND s3.PaperID = s.PaperID
            AND s3.Status = 1
            AND s3.ID <> s.ID
    )
    -- Make sure it's the same customer. Customer number is checked in
    -- join above.
    AND s.PaperID = s2.PaperID
    AND s.Address = s2.Address

这有效,但我想知道子查询方法是最好的解决方案还是有更好的方法?

我想加深对MS SQL的理解,从而加深对我的理解。

2 个答案:

答案 0 :(得分:3)

我认为您的查询过于复杂:

with toupdate as (
      select s.*,
             lag(address) over (partition by subscriberid, paperid order by id) as prev_address,
             lag(status) over (partition by subscriberid, paperid order by id) as prev_status
      from dbo.Subscribers s
     ) 
update toupdate
    set address = prev_address,
        status = prev_status
    where address is null;

答案 1 :(得分:2)

这不是您正在寻找的答案,但它并不适合评论。由于您有冗余数据,我真的不同意表的设计。您不必在address中重复indexaddressSubscribers的数据,也不必像您一样做更新。

我建议使用类似下面的设计,以避免你不得不像你正在做的更新。以下代码是可重新运行的,因此您可以根据需要运行和修改以进行测试。

-- user level information with 1 row per user - address should be linked here
CREATE TABLE #user
    (
      id INT ,
      name NVARCHAR(20) ,
      indexAddress INT
    )

-- all subscriptions - with calculated status compared to current date
CREATE TABLE #subscription
    (
      id INT ,
      startDate DATETIME ,
      endDate DATETIME ,
      staus AS CASE WHEN endDate < GETDATE() THEN 1
                    ELSE 0
               END
    )

-- table to link users with their subscriptions
CREATE TABLE #userSubscription
    (
      userId INT ,
      subscriptionId INT
    )


INSERT  INTO #user
        ( id, name, indexAddress )
VALUES  ( 1, N'bob', 13455 ),
        ( 2, 'dave', 55332 )

INSERT  INTO #subscription
        ( id, startDate, endDate )
VALUES  ( 1, '20160101', '20160201' ),
        ( 8, '20160820', '20161201' ),
        ( 14, '20161228', '20170107' ),
        ( 18, '20170109', NULL ),
        ( 55, '20170101', NULL );   

INSERT  INTO #userSubscription
        ( userId, subscriptionId )
VALUES  ( 1, 1 ) ,
        ( 1, 8 ) ,
        ( 1, 14 ) ,
        ( 1, 18 ) ,
        ( 2, 55 );

-- show active users
SELECT u.name ,
       u.indexAddress ,
       us.userId ,
       us.subscriptionId ,
       s.startDate ,
       s.endDate ,
       s.staus 
FROM  #user u
INNER JOIN #userSubscription us ON u.id = us.userId
INNER JOIN #subscription s ON s.id = us.subscriptionId
WHERE s.staus = 0 -- active

-- show inactive users
SELECT u.name ,
       u.indexAddress ,
       us.userId ,
       us.subscriptionId ,
       s.startDate ,
       s.endDate ,
       s.staus 
FROM  #user u
INNER JOIN #userSubscription us ON u.id = us.userId
INNER JOIN #subscription s ON s.id = us.subscriptionId
WHERE s.staus = 1 -- inactive

-- tidy up
DROP TABLE #subscription
DROP TABLE #user
DROP TABLE #userSubscription