如何获取SQL表中的下一条记录
Posted
技术标签:
【中文标题】如何获取SQL表中的下一条记录【英文标题】:How to get the next record in SQL table 【发布时间】:2009-02-03 01:57:26 【问题描述】:我的 MS SQL 表中有一组记录。以日期为主键。但日期仅适用于工作日,而不适用于连续日。例如:
2000 年 1 月 3 日凌晨 12:00:00 5209.540000000 5384.660000000 5209.540000000 5375.110000000 2000 年 1 月 4 日凌晨 12:00:00 5533.980000000 5533.980000000 5376.430000000 5491.010000000 2000 年 1 月 5 日凌晨 12:00:00 5265.090000000 5464.350000000 5184.480000000 5357.000000000 2000 年 1 月 6 日凌晨 12:00:00 5424.210000000 5489.860000000 5391.330000000 5421.530000000 2000 年 1 月 7 日凌晨 12:00:00 5358.280000000 5463.250000000 5330.580000000 5414.480000000 2000 年 1 月 10 日凌晨 12:00:00 5617.590000000 5668.280000000 5459.970000000 5518.390000000 2000 年 1 月 11 日上午 12:00:00 5513.040000000 5537.690000000 5221.280000000 5296.300000000 2000 年 1 月 12 日 12:00:00 AM 5267.850000000 5494.300000000 5267.850000000 5491.200000000
在此我试图在表中引入一个新列,它的值应该是第 3 列的值减去前一个工作日的第 3 列的值。请帮我写这样的查询。我发现这很困难,因为周末没有日期。
【问题讨论】:
【参考方案1】:有几种方法可以做到这一点。这是一个。
CREATE TABLE MyTable
(
MyDate datetime NOT NULL PRIMARY KEY,
Col2 decimal(14,4) NOT NULL,
Col3 decimal(14,4) NOT NULL,
Col4 decimal(14,4) NOT NULL,
Col5 decimal(14,4) NOT NULL
)
GO
INSERT INTO MyTable
SELECT '1/3/2000 12:00:00 AM', 5209.540000000, 5384.660000000, 5209.540000000, 5375.110000000
UNION ALL
SELECT '1/4/2000 12:00:00 AM', 5533.980000000, 5533.980000000, 5376.430000000, 5491.010000000
UNION ALL
SELECT '1/5/2000 12:00:00 AM', 5265.090000000, 5464.350000000, 5184.480000000, 5357.000000000
UNION ALL
SELECT '1/6/2000 12:00:00 AM', 5424.210000000, 5489.860000000, 5391.330000000, 5421.530000000
UNION ALL
SELECT '1/7/2000 12:00:00 AM', 5358.280000000, 5463.250000000, 5330.580000000, 5414.480000000
UNION ALL
SELECT '1/10/2000 12:00:00 AM', 5617.590000000, 5668.280000000, 5459.970000000, 5518.390000000
UNION ALL
SELECT '1/11/2000 12:00:00 AM', 5513.040000000, 5537.690000000, 5221.280000000, 5296.300000000
UNION ALL
SELECT '1/12/2000 12:00:00 AM', 5267.850000000, 5494.300000000, 5267.850000000, 5491.200000000
GO
CREATE VIEW MyView
AS
SELECT T1.*,
CalculatedColumn = Col3 -
(SELECT Col3 FROM MyTable Q2
WHERE Q2.MyDate = (SELECT MAX(Q1.MyDate)
FROM MyTable Q1
WHERE Q1.MyDate < T1.MyDate)
)
FROM MyTable T1
GO
SELECT * FROM MyView
GO
结果
MyDate Col2 Col3 Col4 Col5 CalculatedColumn
----------------------- --------- --------- --------- --------- ----------------
2000-01-03 00:00:00.000 5209.5400 5384.6600 5209.5400 5375.1100 NULL
2000-01-04 00:00:00.000 5533.9800 5533.9800 5376.4300 5491.0100 149.3200
2000-01-05 00:00:00.000 5265.0900 5464.3500 5184.4800 5357.0000 -69.6300
2000-01-06 00:00:00.000 5424.2100 5489.8600 5391.3300 5421.5300 25.5100
2000-01-07 00:00:00.000 5358.2800 5463.2500 5330.5800 5414.4800 -26.6100
2000-01-10 00:00:00.000 5617.5900 5668.2800 5459.9700 5518.3900 205.0300
2000-01-11 00:00:00.000 5513.0400 5537.6900 5221.2800 5296.3000 -130.5900
2000-01-12 00:00:00.000 5267.8500 5494.3000 5267.8500 5491.2000 -43.3900
【讨论】:
您可能可以优化最里面的 where 子句来限制检查 Q1 中的哪些行。您知道前一行最多会提前 2 或 3 天。 @Mike 它执行 CLUSTERED INDEX SEEK,非常高效。 SQL Server 通常非常擅长自我优化。【参考方案2】:您需要将其分解为 2 个部分。首先是更新现有数据,其次是确保所有新数据都具有正确的附加值。
对于第一部分,请考虑使用 CURSOR。运行可能需要一段时间,但至少你只运行一次。像 FOR 循环一样使用 CURSOR;遍历数据中的每一行,忽略第一行(因为您没有指定在没有上一个日期时如何计算新列的值)。以防万一,您很可能应该按日期升序排序。
在您遍历时,使用变量来存储该行中的值。在循环时,将这些变量复制到以前的行版本中,然后再获取新行。例如,您有一个名为“Col3”的变量和另一个名为“lastCol3”的变量。在循环到下一行(即光标移动到下一行)之前,将 col3 的值复制到 lastCol3 中,然后获得 col3 的新值。现在您有了每行的当前值和以前的值,并且可以调用“update”来更新新列。
对于未来的新数据,您需要确保提供新值,或者如果您希望 SQL Server 执行此操作,请使用存储过程选择最近的行 col3,并使用该值来计算新的插入表格之前的值。
【讨论】:
【参考方案3】:使用自联接和利用 SQLServers 内置日期函数 datepart(dw,@Date)
的 case 语句。
我确实有责任注意到,首先进行这样的转变可能是一个坏主意。
【讨论】:
以上是关于如何获取SQL表中的下一条记录的主要内容,如果未能解决你的问题,请参考以下文章