如何仅使用SQL执行此[复杂]表更新?

时间:2017-06-29 18:09:43

标签: c# sql sql-server database sql-server-2012

我正在进行一些数据库转换,为我的应用程序的下一个版本更新准备数据库。我遇到了一个特定的场景,我在LINQPad中运行C#代码(LINQPad正在运行转换),但是它很慢,我想尝试将其转换为直接SQL。否则看起来使用C#代码转换大约需要两天时间,并且我无法长时间禁用应用程序以实现此目的。在这种情况下,我试图更新之前不存在的列。请考虑以下表格:

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

我试图完成所有这些操作,因为在应用更新中,我按DateAt列对 DR 行进行排序。在当前版本中,如果用户不按顺序添加日期,则有人会重新排列所有数据,因此日期是有序的。正如你可以想象的那样,这是一个浪费时间的浪费,这就是为什么我想让它与入门订单无关,而是显示它应该是什么。

唯一的关系"我有 P DR 表格中Id列的顺序。第一个 P 行是第一个日期,最后一个 P 行是最后一个日期。第一个 DR 行用于第一个日期,最后一个 DR 行用于最后一个日期。

哦,数据库是SQL Server 2012.提前感谢您的帮助!

2 个答案:

答案 0 :(得分: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 s。如果需要,您可以创建另外使用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

答案 1 :(得分:0)

请务必先备份数据库,但带有from子句的更新语句应该可以满足您的需求:

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

效果说明:

如果您在两个表中都没有id的索引,则可能需要在执行此操作之前添加一个索引。如果您的表很大,如果您正在进行全表扫描,则需要一段时间。