我有一个名为VIEWS
的表,其中包含Id、Day、Month、视频名称、浏览器名称。。。但我只对Id、Day和Month感兴趣。
ID可能是重复的,因为用户(ID(可以在多个月内观看多天的视频。
这是对最短日期和最长日期的查询。
SELECT ID, CONCAT(MIN(DAY), '/', MIN(MONTH)) AS MIN_DATE,
CONCAT(MAX(DAY), '/', MAX(MONTH)) AS MAX_DATE,
FROM Views
GROUP BY ID
我想将这个带有两列(MIN_DATE和MAX_DATE(的select插入到带有insert的两个新列中。
如何将插入到查询中?
要执行您正在尝试执行的操作(您的解决方案存在一些问题,请阅读我在下面的评论(,首先需要将新列添加到表中。
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相同的所有行。此外,min/max值将始终在属于同一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