英文:
SQL Server related time range issues
问题
I understand your request, and I will provide the translated portion without any additional content. Here's the translation of your query:
我有一个为N年的按小时记录的数据库。我想从每一年中提取一段时间。例如,从 2-3 21:00:00
到 5-12 09:00:00
。
我想一次查询所有年份中这个时间段的所有数据。有没有办法做到这一点?
表格格式类似于这样:
ID | SID | TT | BC |
---|---|---|---|
1 | 55555 | 2007-01-01 00:00:00.000 | 22 12 18 20 |
2 | 55555 | 2007-01-01 01:00:00.000 | 22 12 18 20 |
3 | 55555 | 2009-02-01 01:00:00.000 | 22 12 18 20 |
4 | 55555 | 2009-03-21 20:00:00.000 | 22 12 18 20 |
5 | 55555 | 2011-04-02 23:00:00.000 | 22 12 18 20 |
6 | 55555 | 2012-07-05 01:00:00.000 | 11 65 10 61 |
7 | 55555 | 2013-08-01 02:00:00.000 | 16 20 6 16 |
SQL Server似乎受到年、月、日或小时范围的限制。尝试使用像MONTH或DAY这样的函数限制它不会产生期望的结果。如果使用循环,可以解决问题,但我仍然想知道是否可以使用SQL集合操作的特殊方法来解决这个问题。欢迎任何想法。我该如何做到这一点?
英文:
I have an hour-by-hour database for N years. I want to extract a period of time in each year. For example, 2-3 21:00:00
to 5-12 09:00:00
.
I want to query all the data in this time period for all the years at once. Is there a way to do this?
The table format is similar to this:
ID | SID | TT | BC |
---|---|---|---|
1 | 55555 | 2007-01-01 00:00:00.000 | 22 12 18 20 |
2 | 55555 | 2007-01-01 01:00:00.000 | 22 12 18 20 |
3 | 55555 | 2009-02-01 01:00:00.000 | 22 12 18 20 |
4 | 55555 | 2009-03-21 20:00:00.000 | 22 12 18 20 |
5 | 55555 | 2011-04-02 23:00:00.000 | 22 12 18 20 |
6 | 55555 | 2012-07-05 01:00:00.000 | 11 65 10 61 |
7 | 55555 | 2013-08-01 02:00:00.000 | 16 20 6 16 |
SQL Server seems to be limited to a year, month, day, or hour range. Trying to limit it with functions like MONTH or DAY doesn't give the desired result. It does work if you use a loop, but I'm still wondering if I can use some special way of solving this problem using only SQL set operation. Any ideas are appreciated. How can I do this?
答案1
得分: 2
最好的方法可能是构建一个包含所有所需日期范围的(可能是虚拟的)表格。例如,您可以使用 GENERATE_SERIES
或 VALUES
构造函数生成年份,然后根据此计算日期。
SELECT
t.*
FROM (VALUES
(2020),
(2021),
(2022),
(2023)
) AS v1(Year)
CROSS APPLY (
SELECT
StartDate = DATETIMEFROMPARTS(v1.Year, 2, 3, 21, 0, 0),
EndDate = DATETIMEFROMPARTS(v1.Year, 5, 12, 9, 0, 0)
) AS v2
JOIN YourTable t
ON t.TT >= v2.StartDate
AND t.TT < v2.EndDate;
英文:
The best way to do that is probably to construct a (possibly virtual) table of all the date ranges you want. For example, you can use GENERATE_SERIES
or a VALUES
constructor to generate the years, then calculate the dates off that.
SELECT
t.*
FROM (VALUES
(2020),
(2021),
(2022),
(2023)
) AS v1(Year)
CROSS APPLY (
SELECT
StartDate = DATETIMEFROMPARTS(v1.Year, 2, 3, 21, 0, 0),
EndDate = DATETIMEFROMPARTS(v1.Year, 5, 12, 9, 0, 0)
) AS v2
JOIN YourTable t
ON t.TT >= v2.StartDate
AND t.TT < v2.EndDate;
答案2
得分: 0
Unfortunately, there's no good way to do this, where "good" is defined as "not needing a separate calculation for every row in the table", but at least it's possible.
Anyway, what I would do is use the default/0 year of 1900 to provide the target month/day/time value as a full datetime. Assuming the Month-Day ordering of the samples, that would look like this in code: 19000203 21:00:00
and 19000512 09:00:00
(for historical reasons, it's safer in SQL Server to use the unseparated ISO-8601 variant for dates).
Then I would transform the values for each record like this to match the year in each row:
DATEADD(Year, Year(TT)-1900, '19000203 21:00:00')
DATEADD(Year, Year(TT)-1900, '19000512 09:00:00')
So you can do a direct comparison:
SELECT *
FROM <table>
WHERE TT >= DATEADD(Year, Year(TT)-1900, '19000203 21:00:00')
AND TT < DATEADD(Year, Year(TT)-1900, '19000512 09:00:00')
Again, I used 1900 because that's the epoch year for SQL Server, but other values can work as well. This isn't the fastest thing in the world, because you need to make a new calculation on each row, which probably also eliminates any index use, but at least it gives good results.
See it work here:
英文:
Unfortunately, there's no good way to do this, where "good" is defined as "not needing a separate calculation for every row in the table", but at least it's possible.
Anyway, what I would do is use the default/0 year of 1900 to provide the target month/day/time value as a full datetime. Assuming the Month-Day ordering of the samples, that would look like this in code: 19000203 21:00:00
and 19000512 09:00:00
(for historical reasons, it's safer in SQL Server to use the unseparated ISO-8601 variant for dates).
Then I would transform the values for each record like this to match the year in each row:
DATEADD(Year, Year(TT)-1900, '19000203 21:00:00')
DATEADD(Year, Year(TT)-1900, '19000512 09:00:00')
So you can do a direct comparison:
SELECT *
FROM <table>
WHERE TT >= DATEADD(Year, Year(TT)-1900, '19000203 21:00:00')
AND TT < DATEADD(Year, Year(TT)-1900, '19000512 09:00:00')
Again, I used 1900 because that's the epoch year for SQL Server, but other values can work as well. This isn't the fastest thing in the world, because you need to make a new calculation on each row, which probably also eliminates any index use, but at least it gives good results.
See it work here:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论