在SQL Server 2008上,我有一个具有以下架构的视图revenue
:
+----------------------------+
| id | year | month | amount |
+----------------------------+
| 1 | 2014 | 11 | 100 |
| 2 | 2014 | 12 | 3500 |
| 3 | 2014 | 12 | 90 |
| 4 | 2015 | 1 | 1000 |
| 5 | 2015 | 2 | 6000 |
| 6 | 2015 | 2 | 600 |
| 7 | 2015 | 3 | 70 |
| 8 | 2015 | 3 | 340 |
+----------------------------+
上面的架构和数据被简化,视图非常大,有数百万行。我无法控制架构,因此无法将字段更改为DATE或类似字段。年和月字段是INT。
我正在寻找一个SELECT语句,它从任意月份开始返回x个月的数据。例如滚动3个月,滚动5个月等等。
我想出的是:
SELECT
rolling_date,
amount
FROM (SELECT CAST('01/' + RIGHT('00' + CONVERT(VARCHAR(2), month), 2) + '/' + CAST(year AS VARCHAR(4)) AS DATE) AS rolling_date,
amount
FROM [revenue]
) date_revenue
WHERE rolling_date BETWEEN CAST('01/12/2014' AS DATE) AND CAST('31/02/2015' AS DATE)
然而,......
Error line 1: Conversion failed when converting date and/or time from character string..
答案 0 :(得分:3)
首先,转换错误发生是因为没有2月31日。我在下面的示例中将其更改为2月28日。
由于您的表包含数百万行,因此最好避免对表中的数据进行任何转换或计算。而是将输入转换为与您的表匹配的格式。这样你就可以利用索引。
以下示例非常有效,尤其是如果您可以在Year, Month
上创建非聚集索引。
declare @start datetime = '2014-12-01'
declare @end datetime = '2015-02-28'
declare @startyear int = datepart(year, @start)
declare @startmonth int = datepart(month, @start)
declare @endyear int = datepart(year, @end)
declare @endmonth int = datepart(month, @end)
select * from revenue
where (Year > @startyear OR (Year = @startyear AND Month >= @startmonth))
AND (Year < @endyear OR (Year = @endyear AND Month <= @endmonth))
编辑:以下示例从处理角度来看是相同的,并且不会声明任何新变量:
select * from revenue
where (Year > datepart(year, @start)
OR (Year = datepart(year, @start) AND Month >= datepart(month, @start)))
AND (Year < datepart(year, @end)
OR (Year = datepart(year, @end) AND Month <= datepart(month, @end)))
编辑2:如果你能够通过年度&amp;单独月份,你可以运行:
select * from revenue r
where (Year > 2014 OR (Year = 2014 AND Month >= 12))
AND (Year < 2015 OR (Year = 2015 AND Month <= 2))
答案 1 :(得分:2)
您可以对您的年份进行整数比较:
SELECT
id, yr, month, amount
FROM
Magazines
WHERE yr*100 + month >= 201412 AND yr*100 + month <= 201503
但这不会将您的年月作为日期返回。这是一项要求吗?
答案 2 :(得分:0)
SQL服务器版本是2012及更高版本,您可以使用DATEFROMPARTS方法来构建年和月的日期。如果没有,请将您的查询修改为:
SELECT
rolling_date,
amount
FROM (SELECT CAST(
CAST(year AS VARCHAR(4)) +
RIGHT('0' + CAST(month AS VARCHAR(2)), 2) +
RIGHT('0' + CAST('01' AS VARCHAR(2)), 2)
AS DATE) AS rolling_date,
amount
FROM [revenue]
) date_revenue
WHERE rolling_date BETWEEN CAST('2014/02/01' AS DATE) AND CAST('2015/12/31' AS DATE)
答案 3 :(得分:0)
我现在无法在这台机器上查看我的语法,但我会尝试这样的事情。基本上,我把你的开始月份和年份作为日期,并以01作为日期,然后我使用它以相同的方式将每一行与铸造进行比较,使用this answer中的技术。
declare @n integer
set @n = 3
declare @startmonth as integer
set @startmonth = 12
declare @startyear as integer
set @startyear = 2014
declare @startdatetime as datetime
set @startdatetime =
CAST(@startyear AS VARCHAR(4)) +
RIGHT('0' + CAST(@startmonth AS VARCHAR(2)), 2) +
'01'
AS DATETIME)
select
*
from revenue
where
CAST(
CAST(year AS VARCHAR(4)) +
RIGHT('0' + CAST(month AS VARCHAR(2)), 2) +
'01'
AS DATETIME) >= @startdatetime
and
CAST(
CAST(year AS VARCHAR(4)) +
RIGHT('0' + CAST(month AS VARCHAR(2)), 2) +
'01'
AS DATETIME)
<
dateadd(month, @n, @startdatetime)