SQL Server相关的时间范围问题。

huangapple go评论71阅读模式
英文:

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:005-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_SERIESVALUES 构造函数生成年份,然后根据此计算日期。

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;

db<>fiddle

英文:

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 &gt;= v2.StartDate
 AND t.TT &lt; v2.EndDate;

db<>fiddle

答案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:

https://dbfiddle.uk/t1hR5MAd

英文:

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, &#39;19000203 21:00:00&#39;)
DATEADD(Year, Year(TT)-1900, &#39;19000512 09:00:00&#39;)

So you can do a direct comparison:

SELECT *
FROM &lt;table&gt;
WHERE   TT &gt;= DATEADD(Year, Year(TT)-1900, &#39;19000203 21:00:00&#39;)
    AND TT &lt;  DATEADD(Year, Year(TT)-1900, &#39;19000512 09:00:00&#39;)

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:

> https://dbfiddle.uk/t1hR5MAd

huangapple
  • 本文由 发表于 2023年7月31日 22:03:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/76804392.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定