has*_*has 1 performance sql-server subquery sql-server-2012 query-performance
如果ID = 01234
并且此 ID 在一个月内进行了 3 次交易,如下所示:
***DAY_no Balance***
1/1/2018 5000
10/1/2018 10000
15/1/2018 12000
Run Code Online (Sandbox Code Playgroud)
我想要这样的数据:
***DAY_no Balance***
1/1/2018 5000
2/1/2018 5000
3/1/2018 5000
4/1/2018 5000
5/1/2018 5000
6/1/2018 5000
7/1/2018 5000
8/1/2018 5000
9/1/2018 5000
10/1/2018 10000
11/1/2018 10000
12/1/2018 10000
13/1/2018 10000
14/1/2018 10000
15/1/2018 12000
16/1/2018 12000
17/1/2018 12000
18/1/2018 12000
19/1/2018 12000
20/1/2018 12000
21/1/2018 12000
22/1/2018 12000
23/1/2018 12000
24/1/2018 12000
25/1/2018 12000
26/1/2018 12000
27/1/2018 12000
28/1/2018 12000
29/1/2018 12000
30/1/2018 12000
31/1/2018 12000
Run Code Online (Sandbox Code Playgroud)
您可以使用日历表:
Run Code Online (Sandbox Code Playgroud)CREATE TABLE Calendar(cDate datetime, cDay int, cDayOfWeek int, cDayName varchar(20), cMonth int); DECLARE @date date = '20180101'; WHILE @date <= '20180131' BEGIN INSERT INTO Calendar VALUES (@date, DAY(@date), DATEPART(weekday, @date), DATENAME(weekday, @date), MONTH (@date)); SET @date = DATEADD(day, 1, @date); END CREATE TABLE Mov (Day_no date, Balance int); INSERT INTO Mov VALUES ('20180101', 5000), ('20180110', 10000), ('20180115', 12000); GO
34 行受影响
Run Code Online (Sandbox Code Playgroud)SELECT cDAte, (SELECT TOP 1 Balance FROM Mov WHERE Day_no <= cDate ORDER BY Day_no DESC) Balance FROM Calendar WHERE cMonth = 1; GO
日期 | 平衡 :------------------ | ------: 01/01/2018 00:00:00 | 5000 02/01/2018 00:00:00 | 5000 03/01/2018 00:00:00 | 5000 04/01/2018 00:00:00 | 5000 05/01/2018 00:00:00 | 5000 06/01/2018 00:00:00 | 5000 07/01/2018 00:00:00 | 5000 08/01/2018 00:00:00 | 5000 09/01/2018 00:00:00 | 5000 10/01/2018 00:00:00 | 10000 11/01/2018 00:00:00 | 10000 12/01/2018 00:00:00 | 10000 13/01/2018 00:00:00 | 10000 14/01/2018 00:00:00 | 10000 15/01/2018 00:00:00 | 12000 16/01/2018 00:00:00 | 12000 17/01/2018 00:00:00 | 12000 18/01/2018 00:00:00 | 12000 19/01/2018 00:00:00 | 12000 20/01/2018 00:00:00 | 12000 21/01/2018 00:00:00 | 12000 22/01/2018 00:00:00 | 12000 23/01/2018 00:00:00 | 12000 24/01/2018 00:00:00 | 12000 25/01/2018 00:00:00 | 12000 26/01/2018 00:00:00 | 12000 27/01/2018 00:00:00 | 12000 28/01/2018 00:00:00 | 12000 29/01/2018 00:00:00 | 12000 30/01/2018 00:00:00 | 12000 31/01/2018 00:00:00 | 12000
dbfiddle在这里
您应该始终有一个日历表来帮助解决此类问题(并且您应该尽量避免将 SQL Server 中的任何内容视为“循环”——它已针对集合进行了优化)。
-- this produces all the days from 2000-01-01 through 2099-12-31
CREATE TABLE dbo.Calendar(d date PRIMARY KEY);
DECLARE @s date = '20000101', @e date = '20991231';
INSERT dbo.Calendar(d)
SELECT DATEADD(DAY, r-1, @s)
FROM ( SELECT TOP (DATEDIFF(DAY, @s, @e)+1)
r = ROW_NUMBER() OVER (ORDER BY o.[object_id])
FROM sys.all_objects AS o
CROSS JOIN sys.all_objects AS c
) AS x;
Run Code Online (Sandbox Code Playgroud)
一旦您设置了日历表,就可以轻松地使用查询LEFT JOIN
来填补这样的空白。假设您有以下数据:
CREATE TABLE #sample
(
DAY_no date,
Balance int
);
INSERT #sample(DAY_no,Balance)
VALUES('20180101', 5000 ),
('20180110', 10000),
('20180115', 12000);
Run Code Online (Sandbox Code Playgroud)
查询是(我什至使用了一个变量来定义您之后的月份):
DECLARE @month date = DATEFROMPARTS(2018,1,1);
SELECT DAY_no = c.d,
MAX(s.Balance)
FROM dbo.Calendar AS c
LEFT OUTER JOIN #sample AS s
ON s.DAY_no <= c.d
WHERE c.d >= @month
AND c.d < DATEADD(MONTH, 1, @month)
GROUP BY c.d
ORDER BY c.d;
Run Code Online (Sandbox Code Playgroud)
当然,如果您的第一个数据点在本月的第一天之后,您将不得不使查询更加复杂,因为您需要从上个月提取最后一个已知余额。
有关日历表的更多信息,请参阅此提示。
归档时间: |
|
查看次数: |
16931 次 |
最近记录: |