用于更新另一列的三列的SQL语句

时间:2015-12-14 19:06:40

标签: sql-server

我的表格结构如下:

CREATE TABLE [dbo].[Ontledings](
[ont_ID] [int] IDENTITY(1,1) NOT NULL,
[plaasno] [varchar](50) NOT NULL,
[plaasnaam] [varchar](50) NOT NULL,
[blokno] [varchar](50) NOT NULL,
[plaasblok] [varchar](50) NULL,
[area] [varchar](50) NOT NULL,
[analisedatum] [date] NOT NULL,
[name3] [varchar](50) NULL,
[kultivar] [varchar](50) NOT NULL,
[wingklas] [varchar](50) NOT NULL,
[kultklas] [varchar](50) NULL,
[suiker] [real] NOT NULL,
[pH] [real] NOT NULL,
[suur] [real] NOT NULL,
[last] [date] NULL,
[secondlast] [date] NULL,
[thirdlast] [date] NULL,
 CONSTRAINT [PK_Ontledings] PRIMARY KEY CLUSTERED 
(
[ont_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,   ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

在更新之前,表格如下所示(仅包括相关列):
Before update

对于每一行,我需要根据analisedatum列(仅针对当前年份)更新该行的第三,第二和最后日期的最后三列。这需要对plaasblok相同的所有行进行。

结果表应如下所示:
After update

3 个答案:

答案 0 :(得分:0)

编辑,

首先,您的结构不是很好,因为您在某些列中会有不同的行具有相同的值,但它并不好。

更好的结构是使用不同的表来处理每个 plaasblok 的3个最早的日期。为此,您可以从 Ontledings 表中删除 last secondlast thirdlast 列,并使用这些列创建另一个表。然后创建一个进程 SELECT Ontledings 表中的3个最早的日期,每个 plaasblok INSERT 新表。有了这个,你就可以避免在某些列中有一个包含相同值的行的大表。

新表格如下:

plaasblok | last    | secondlast | thirdlast
03706A1   | 18/3/15 | 17/3/15    | 13/3/315
03706A2   | 17/2/15 | 16/2/15    | 10/2/315
03706A3   | 18/3/15 | 17/3/15    | 13/3/315
(...)

此过程可以执行以下 SELECT 以获得您想要的结果:

SELECT
   A.plaasblok,
   MAX(A.analisedatum) as last,
   MAX(B.analisedatum) as secondlast,
   MAX(C.analisedatum) as thirdlast
FROM Ontledings A
JOIN Ontledings B ON B.plaasblok = A.plaasblok AND B.analisedatum < A.analisedatum
JOIN Ontledings C ON C.plaasblok = B.plaasblok AND C.analisedatum < B.analisedatum
GROUP BY A.plaasblok
ORDER BY A.plaasblok ASC;

答案 1 :(得分:0)

这涉及在子查询中进行一些自我加入以解释要找到的多个日期:

UPDATE O
SET O.last = Z.last
,   O.secondlast = Z.secondlast
,   O.thirdlast = Z.thirdlast
FROM Ontledings O
JOIN (
    SELECT X.plaasblok, MAX(X.analisedatum) AS last, MAX(P.analisedatum) AS secondlast, MAX(Q.analisedatum) AS thirdlast
    FROM Ontledings X
    JOIN Ontledings P ON P.plaasblok = X.plaasblok AND P.analisedatum < X.analisedatum
    JOIN Ontledings Q ON Q.plaasblok = P.plaasblok AND Q.analisedatum < P.analisedatum
    GROUP BY X.plaasblok
) AS Z
ON O.plaasblok = Z.plaasblok

请注意,您可以使用稍微复杂的SELECT检查值 - 请注意每个联接的MAX日期如何级联以确保最近一个日期的有效性:

SELECT O.plaasblok, MAX(O.analisedatum) AS last, MAX(P.analisedatum) AS secondlast, MAX(Q.analisedatum) AS thirdlast
FROM Ontledings O
JOIN Ontledings P ON P.plaasblok = O.plaasblok AND P.analisedatum < O.analisedatum
JOIN Ontledings Q ON Q.plaasblok = P.plaasblok AND Q.analisedatum < P.analisedatum
GROUP BY O.plaasblok
ORDER BY O.plaasblok

答案 2 :(得分:0)

以下是使用窗口函数row_number()的解决方案。首先,您按降序日期对plaasblok组中的行进行编号。然后你需要3个连接并更新:

;with cte as(select *, row_number() over(partition by plaasblok order by analisedatum desc) rn 
             from Ontledings)

update t set [last] = c1.analisedatum,
             [secondlast] = c2.analisedatum,
             [thirdlast] = c3.analisedatum
from Ontledings t
left join cte c1 on t.plaasblok = c1.plaasblok and c1.rn = 1
left join cte c2 on t.plaasblok = c2.plaasblok and c2.rn = 2
left join cte c3 on t.plaasblok = c3.plaasblok and c3.rn = 3