2017-01-12 98 views
0

我有一個表報紙訂戶數據記錄:最新更新與舊記錄

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

IndexAddress是我的內部地址表中的參考,我保持「正確」的地址(你woulnd't認爲如何許多人不知道他們住在哪裏)。地址是客戶提供的地址。

每當用戶結束他的訂閱,我保存數據,當他續訂他的訂閱時,我想重新從我表格中的舊subscrption行中獲取舊的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的行中獲取信息,因爲數據庫MIGHT中的舊信息是錯誤的(在這種情況下,它不是,但它可能)。

這是我的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的理解,從而提出我的問題。

+0

我可以問,SubscriberID是什麼鏈接,以及那裏有什麼信息?我認爲這裏有一個設計問題來解決這個問題,它可以改善問題並減少對更復雜代碼的需求。 – Tanner

回答

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; 
+0

備註:LAG 2012+ – Tanner

1

這是不是你要找的答案,但它不是真正適合評論。因爲您有冗餘數據,所以我並不完全同意表格的設計。您不必重複addressindexaddress中的數據Subscribers或像您一樣進行更新。

我會建議一個像下面這樣的設計,可以避免你不得不像你正在做的那樣更新。下面的代碼是可重新運行的,所以你可以運行和修改,如果需要測試它。

-- 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