鉴于我有2个日期范围(之前的日期和当前日期),我想比较这2个日期范围的值。
比较方法:
示例
数据库表"数据":
date | value
-------------|------
2018-01-01 | 3
2018-01-02 | 5
2018-01-03 | 8
2018-01-04 | 6
2018-02-04 | 4
2018-02-05 | 2
2018-02-06 | 7
2018-02-07 | 0
鉴于日期范围:(当前)2018-02-04至2018-02-07,(上一页)2018-01-01至2018-01-03
期望的输出:
curDate | curValue | preDate | preValue
-------------|----------|-------------|---------
2018-02-04 | 4 | 2018-01-01 | 3
2018-02-05 | 2 | 2018-01-02 | 5
2018-02-06 | 7 | 2018-01-03 | 8
2018-02-07 | 0 | NULL | 0
我现在陷入了连接状态,我当前的SQL就像:
DECLARE @currentStartDateTime datetime = '2018-02-04 00:00:00'
DECLARE @currentEndDateTime datetime = '2018-02-07 23:59:59'
DECLARE @previousStartDateTime datetime = '2018-01-01 00:00:00'
DECLARE @previousEndDateTime datetime = '2018-01-03 23:59:59'
SELECT cur.[date] AS [curDate]
,ISNULL(cur.[total], 0) AS [curTotal]
,pre.[date] AS [preDate]
,ISNULL(pre.[total], 0) AS [preTotal]
FROM (
SELECT * FROM [data]
WHERE [date] BETWEEN @currentStartDateTime AND @currentEndDateTime
) cur
FULL OUTER JOIN (
SELECT * FROM [data]
WHERE [date] BETWEEN @previousStartDateTime AND @previousEndDateTime
) pre
ON cur.[date] = DATEADD(day, 1, pre.[date]) -- <<< Stuck in this part
答案 0 :(得分:1)
当您提出要求时,最好将所有DDL和插入包含在一起。
DROP TABLE data;
CREATE TABLE data
(
date DATE,
value INT
);
GO
INSERT INTO data
VALUES
('2018-01-01', 3),
('2018-01-02', 5),
('2018-01-03', 8),
('2018-01-04', 6),
('2018-02-04', 4),
('2018-02-05', 2),
('2018-02-06', 7),
('2018-02-07', 0);
DECLARE @currentStartDateTime DATETIME = '2018-02-04 00:00:00';
DECLARE @currentEndDateTime DATETIME = '2018-02-07 23:59:59';
DECLARE @previousStartDateTime DATETIME = '2018-01-01 00:00:00';
DECLARE @previousEndDateTime DATETIME = '2018-01-03 23:59:59';
SELECT a.date curDate,
a.value curValue,
b.date preDate,
COALESCE(b.value, 0) preValue
FROM
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY date) rn
FROM data
WHERE date
BETWEEN @currentStartDateTime AND @currentEndDateTime
) a
LEFT JOIN
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY date) rn
FROM data
WHERE date
BETWEEN @previousStartDateTime AND @previousEndDateTime
) b
ON a.rn = b.rn;
答案 1 :(得分:1)
我要做的第一件事是为您的日期范围创建公用表表达式,每个表达式都有两列:一列包含数据值,另一列包含行号值。这样,按第n个值加入就很容易了。
所以这是我建议的解决方案:
首先,创建并填充样本表(请在将来的问题中将此步骤保存起来)
DECLARE @data As Table
(
[date] DATE,
[value] INT
);
INSERT INTO @data
VALUES
('2018-01-01', 3),
('2018-01-02', 5),
('2018-01-03', 8),
('2018-01-04', 6),
('2018-02-04', 4),
('2018-02-05', 2),
('2018-02-06', 7),
('2018-02-07', 0);
现在,我已将@currentStartDateTime
从2018-02-04
更改为2018-02-03
,
确保我还返回表格中没有的行(请确保您的样本数据涵盖所有要求)
DECLARE @currentStartDateTime datetime = '2018-02-03 00:00:00',
@currentEndDateTime datetime = '2018-02-07 23:59:59',
@previousStartDateTime datetime = '2018-01-01 00:00:00',
@previousEndDateTime datetime = '2018-01-03 23:59:59'
现在,我的解决方案似乎非常麻烦,因为我想详细显示所有步骤。 您可以简化它。
首先,计算天数的最大日期差异
然后,创建一个从1到该差值+ 1的数字cte
然后,为每个范围创建日历cte,
然后是最后的cte,在范围之间进行完全连接,
并从最后一个cte中选择左边两次加入数据表。
-- This allows us to use the smallest possible tally cte.
DECLARE @MaxDateDiff int;
SELECT @MaxDateDiff = MAX(d)
FROM (
VALUES (DATEDIFF(DAY, @currentStartDateTime, @currentEndDateTime)),
(DATEDIFF(DAY, @previousStartDateTime, @previousEndDateTime))
) v(d) -- I like table value constructors :-)
;WITH Tally AS
(
SELECT TOP (@MaxDateDiff + 1) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) As Number
FROM sys.objects a
-- if your database is very small (number of tables, procedures ect'),
-- you might want to unremark the next row
-- CROSS JOIN sys.objects b
),
CurrentRange AS
(
SELECT DATEADD(DAY, Number-1, @currentStartDateTime) As [Date], Number
FROM Tally
-- we need the where clause in case the other range is bigger...
WHERE DATEADD(DAY, Number-1, @currentStartDateTime) <= @currentEndDateTime
),
PreviousRange AS
(
SELECT DATEADD(DAY, Number-1, @previousStartDateTime) As [Date], Number
FROM Tally
WHERE DATEADD(DAY, Number-1, @previousStartDateTime) <= @previousEndDateTime
),
BothRanges AS
(
SELECT C.Date As CurDate, P.Date As PreDate
FROM CurrentRange As C
FULL JOIN PreviousRange As P ON C.Number = P.Number
)
SELECT CurDate, ISNULL(c.Value, 0) as CurValue, PreDate, ISNULL(p.Value, 0) as PreValue
FROM BothRanges
LEFT JOIN @data AS c ON CurDate = c.[Date]
LEFT JOIN @data AS p ON PreDate = p.[Date]
结果:(请记住,@currentStartDateTime
与问题上的CurDate CurValue PreDate PreValue
03.02.2018 00:00:00 0 01.01.2018 00:00:00 3
04.02.2018 00:00:00 4 02.01.2018 00:00:00 5
05.02.2018 00:00:00 2 03.01.2018 00:00:00 8
06.02.2018 00:00:00 7 NULL 0
07.02.2018 00:00:00 0 NULL 0
不同)
include("conn.php");
$ne_lat = $_POST['a'];
$ne_lon = $_POST['b'];
$sw_lat = $_POST['c'];
$sw_lon = $_POST['d'];
$result = mysqli_query($con,"SELECT schoolname, latitude, longitude, total_students, act_composite_25, schoolid, (sat_critread_25+sat_math_25) as sat, (100 * admissions_total/applicants_total) as admrate, degree_bachelor, degree_masters, url, city, usstate, tuition_outstate, tuition_instate FROM usschools WHERE
(CASE WHEN $ne_lat < $sw_lat
THEN latitude BETWEEN $ne_lat AND $sw_lat
ELSE latitude BETWEEN $sw_lat AND $ne_lat
END)
AND
(CASE WHEN $ne_lon < $sw_lon
THEN longitude BETWEEN $ne_lon AND $sw_lon
ELSE longitude BETWEEN $sw_lon AND $ne_lon
END) and degree_bachelor = 1 order by act_composite_25 desc limit 20");
if (!$result) {
printf("Error: %s\n", mysqli_error($con));
exit();
}
while ($row = $result->fetch_assoc()) {
$data[] = $row;
}