要执行您正在尝试执行的操作(您的解决方案存在一些问题,请阅读下面的我的 cmets),首先您需要将新列添加到表中。
ALTER TABLE Views ADD MIN_DATE VARCHAR(10)
ALTER TABLE Views ADD MAX_DATE VARCHAR(10)
然后你需要UPDATE你的新列(不是INSERT,因为你不想要新行)。确定每个ID 的最小值/最大值,然后将结果连接回表以便能够更新每一行。您无法直接从 GROUP BY 更新,因为行已分组并丢失其原始行。
;WITH MinMax
(
SELECT
ID,
CONCAT(MIN(V.DAY), '/', MIN(V.MONTH)) AS MIN_DATE,
CONCAT(MAX(V.DAY), '/', MAX(V.MONTH)) AS MAX_DATE
FROM
Views AS V
GROUP BY
ID
)
UPDATE V SET
MIN_DATE = M.MIN_DATE,
MAX_DATE = M.MAX_DATE
FROM
MinMax AS M
INNER JOIN Views AS V ON M.ID = V.ID
我在这个设计中看到的问题是:
-
存储聚合列:您通常只想为性能问题执行此操作(我认为这里不是这种情况),因为查询聚合(分组)行会更快,因为行数较少读书。问题是每次更新原始行之一时,您都必须更新分组值,这是额外的处理时间。另一种选择是定期更新聚合值,但您必须接受在一段时间内,分组值并不能真正代表跟踪表。
-
将聚合列与它们正在聚合的数据保持在同一个表中:这是规范化问题。更新或插入行将触发更新具有相同 ID 的所有行,因为最小值/最大值可能已更改。此外,最小/最大值将始终在属于同一 ID 的所有行上重复,这是您浪费的额外空间。如果必须保存聚合数据,则需要将其保存在不同的表中,这会导致我在上一点列出的问题。
-
使用文本数据类型存储日期:您总是希望使用正确的 DATETIME 数据类型来处理日期。这不仅可以使用DATEADD 或DATEDIFF 等日期函数,还可以节省空间(存储日期的varchars 需要比DATETIME 更多的字节)。我没有在您的查询中看到年份部分,应该考虑计算最小值/最大值(这可能取决于您在此表上存储的内容)。
-
计算最小值/最大值不正确:如果您有以下行:
ID DAY MONTH
1 5 1
1 3 2
您查询的当前结果将是3/1 作为MIN_DATE 和5/2 作为MAX_DATE,我相信这不是您想要找到的。这里最低的应该是 1 月 5 日,最高的应该是 2 月 3 日。这是将日期部分存储为独立值而不是将整个日期存储为 DATETIME 的结果。
对于这种情况,您通常想要做的是直接对需要分组数据的查询进行分组,因此您将对需要最小/最大值的SELECT 执行GROUP BY。拥有ID 的索引将使分组非常快。因此,您节省了用于保存聚合值的存储空间,而且结果始终是您查询时的真实分组结果。
应该是这样的:
;WITH MinMax
(
SELECT
ID,
CONCAT(MIN(V.DAY), '/', MIN(V.MONTH)) AS MIN_DATE, -- Date problem (varchar + min/max computed seperately)
CONCAT(MAX(V.DAY), '/', MAX(V.MONTH)) AS MAX_DATE -- Date problem (varchar + min/max computed seperately)
FROM
Views AS V
GROUP BY
ID
)
SELECT
V.*,
M.MIN_DATE,
M.MAX_DATE
FROM
MinMax AS M
INNER JOIN Views AS V ON M.ID = V.ID