2017-06-29 58 views
1

我正在做一些數據庫轉換,爲我的應用的下一個版本更新準備數據庫。我遇到了一個特定的場景,我在LINQPad中使用C#代碼(LINQPad正在運行轉換),但它的速度很慢,我想嘗試將它轉換爲直接的SQL。否則,看起來轉換將花費大約兩天的時間使用C#代碼,並且我無法禁用該應用程序很長時間才能實現。在場景中,我試圖更新以前不存在的列。考慮下面的表:如何才能使用SQL執行此[複雜]表更新?

表J中(對於@maccettura)

------ 
| Id | 
------ 
| 1 | 
------ 

表P中

------------------------- 
| Id | JId | DateAt  | 
------------------------- 
| 1 | 1 | 2017-01-01 | 
| 2 | 1 | 2017-02-01 | 
| 3 | 1 | 2017-03-01 | 
------------------------- 

表d

------------ 
| Id | JId | 
------------ 
| 1 | 1 | 
| 2 | 1 | 
| 3 | 1 | 
------------ 

表DR

--------------------- 
| Id | DId | DateAt | 
--------------------- 
| 1 | 1 | NULL | 
| 2 | 1 | NULL | 
| 3 | 2 | NULL | 
| 4 | 2 | NULL | 
| 5 | 3 | NULL | 
| 6 | 3 | NULL | 
--------------------- 

我想更新表DR,以便日期填寫,數據如下:

------------------------- 
| Id | DId | DateAt  | 
------------------------- 
| 1 | 1 | 2017-01-01 | 
| 2 | 1 | 2017-02-01 | 
| 3 | 2 | 2017-01-01 | 
| 4 | 2 | 2017-02-01 | 
| 5 | 3 | 2017-01-01 | 
| 6 | 3 | 2017-02-01 | 
------------------------- 

我似乎沒有能夠在SQL中表示它。我已經嘗試了用選擇進入臨時表的方法,嘗試按行號進行匹配等等,但是我只是沒有足夠的熟練的SQL來使它工作。如果有人能指引我正確的方向,我會很感激。如果這有什麼差別,這裏的UI形式的樣子:

  -----------------    ------------- 
      | D.Id | D.Id |    | 1 | 2 | 3 | 
---------------------------- => ------------------------ 
| P.DateAt | DR.Id | DR.Id | | 1/1/2017 | 1 | 3 | 5 | 
| P.DateAt | DR.Id | DR.Id | | 1/2/2017 | 2 | 4 | 6 | 
---------------------------- ------------------------ 

我試圖做到這一切,因爲在應用程序更新我的DR行由DateAt列進行排序。在當前版本中,如果用戶按順序添加日期,則有人會重新排列所有數據,以便日期合適。正如你可以想象的那樣,這是對時間的巨大浪費,這就是爲什麼我想讓它與輸入順序無關的原因,但是應該如此顯示它。

唯一的「關係」我是Id列在PDR表的順序。第一行是P行是第一個日期,最後一行是最後一個日期。第一行爲DR行爲第一個日期,最後一行爲DR行爲最後一個日期。

哦,數據庫是SQL Server 2012.在此先感謝您的幫助!

+1

我錯過了什麼嗎?你如何期望從表'P'獲得任何東西?如果'DR'有'DId',那麼你可以連接到'D',但是'P'的PK/FK在哪裏? – maccettura

+0

@maccettura,對不起,我想我沒有清醒過來寫一個完整的問題,但是你是正確的,有一個父表** J **,我省略了。表** P **和** D **與它有關。 – Gup3rSuR4c

+1

最後一行真的應該是'6 | 4 | 2017-02-01'嗎?而不是'6 | 4 | 2017-01-01'? –

回答

1

這將工作:

UPDATE DR 
SET DR.DATEAT = P.DATEAT 
FROM (SELECT ID, DId, DATEAT, ROW_NUMBER() OVER (PARTITION BY DId ORDER BY ID) RN 
     FROM DR) DR 
JOIN P ON P.ID = DR.RN 

這基本上是說,如果它是一個新的DId的第一行,然後從表P,然後第二行第二日期等

使用第一次約會

SELECT看到的邏輯:

SELECT * 
FROM (SELECT ID, DId, DATEAT, ROW_NUMBER() OVER (PARTITION BY DId ORDER BY ID) RN 
     FROM DR) DR 
JOIN P ON P.ID = DR.RN 

SELECT結果:

SELECT results

DR更新後:

DR after update

編輯 這聽起來像P表沒有可靠id秒。如果需要,您可以創建另一個使用ROW_NUMBER()

SELECT * 
FROM (SELECT ID, DId, DateAt, ROW_NUMBER() OVER (PARTITION BY DId ORDER BY ID) RN 
    FROM DR) DR 
JOIN (SELECT DateAt, ROW_NUMBER() OVER (ORDER BY DateAt ASC) as ID 
     FROM P 
    ) P ON P.ID = DR.RN 
+0

謝謝你的例子!我正在測試剛剛恢復和清理的備份上的SELECT,但我沒有得到任何結果。我認爲這是因爲** P **上的'JOIN'。 ** P **也需要有行號才能將它與** DR **對齊。 ** DR **否則看起來應該如此。如果我可能有點不禮貌,請問您還可以將** P **和** D **與他們的父母** **表聯繫起來,否則我有一種感覺,它將成爲免費的所有更新運行時?感謝你目前的幫助! – Gup3rSuR4c

+0

@ Gup3rSuR4c Np,但我很困惑,它不工作。我繼續創建這些表格並截取了我的結果。你可以忽略最後的記錄,我在看到你的編輯之前使用了'DId = 4',它應該是'3'。 –

+0

@ Gup3rSuR4c關於表** J **,它似乎可以作爲J.ID = P.JID'上的JOIN J加入,但它不會影響更新。 :P –

0

確保備份數據庫第一,但與from條款的更新語句應該做你需要的東西:

update dr 
set 
    dr.DateAt = p.DateAt 
from 
    p 
where 
    dr.id = p.id 

性能注:

如果你不已經有一個兩個表的id上的索引,你可能會希望在做這個之前添加一個。如果你的桌子很大,如果你正在進行全表掃描,這將需要一段時間。