我有一个每月有一行的表,金额存储在不同的列中(DAY1,DAY2 ... DAY31)。我创建了一个视图,使用unpivot将其拆分为每天一行,以便我可以对给定的日期范围进行计算。
当我尝试通过仅选择某个日期范围来使用视图时,只要我在表格中有DAY29..DAY31,它就会出错。如果表中包含的日期最多只有28天,那么它可以正常工作。
不幸的是,更改表结构并不是一个真正的选项,我尝试使用内联函数做同样的事情,但它最终会出现同样的错误
Msg 242,Level 16,State 3,Line 52 nvarchar数据的转换 键入日期时间数据类型会导致超出范围的值。
这是我的表:
StatusBar
这是我的观点:
CREATE TABLE CONSUMPTION (
ID int NOT NULL,
YEAR int NOT NULL,
MONTH int NOT NULL,
DAY1 int NULL,
DAY2 int NULL,
DAY3 int NULL,
DAY31 int NULL,
CONSTRAINT TEST_PK PRIMARY KEY CLUSTERED (ID, YEAR, MONTH)
)
insert into CONSUMPTION values (1,2015,1,10,20,30,310)
insert into CONSUMPTION values (1,2015,2,10,20,30,NULL)
如果我像这样运行它,它可以正常工作:
create view CONSUMPTION_CALENDAR as
select
ID,
YEAR,
MONTH,
convert(datetime, substring(COLNAME, 4,2) + '.' + convert(varchar, [MONTH]) + '.' + convert(varchar, [YEAR]), 104) as CONSDATE,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot (CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY31)) as UP
go
但是如果我添加标准,它会返回数据,但也会失败:
select * from CONSUMPTION_CALENDAR
是否有任何解决方法可以选择某个日期范围?
编辑:视图中的数据:
select * from CONSUMPTION_CALENDAR where CONSDATE >= '20150101'
SQL Fiddle中的示例。
答案 0 :(得分:1)
选项1
创建一个日期表,其日期格式合适,例如:可以与unpivot一起加入的D.M.YYYY
。这样就没有从unpivot字符串到日期的转换,所以它不会失败。
create view CONSUMPTION_CALENDAR as
select
P.ID,
C.DAY,
P.MONTH,
P.YEAR,
C.CALENDARDATE as CONSDATE,
P.CONSKG
from (
select
ID,
YEAR,
MONTH,
ltrim(substring(COLNAME, 4,2)) + '.' + convert(varchar(2), [MONTH]) + '.' + convert(varchar(4), [YEAR]) as STOCKDATESTR,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot
(CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7,DAY8,DAY9,DAY10,DAY11,DAY12,DAY13,DAY14,DAY15,DAY16,DAY17,DAY18,DAY19,DAY20,DAY21,DAY22,DAY23,DAY24,DAY25,DAY26,DAY27,DAY28,DAY29,DAY30,DAY31)) as UP
) P
join CALENDAR C on C.DATESTR = P.STOCKDATESTR
CALENDAR表的日期格式为D.M.YYYY
,DATESTR中没有前导零,CALENDARDATE为Date
。
选项2
当NULLS更改为1.1.1900时,fetch似乎也能正常工作:
create view CONSUMPTION_CALENDAR as
select
ID,
YEAR,
MONTH,
convert(datetime,
case when CONSKG is NULL then '1.1.1900' else
substring(COLNAME, 4,2) + '.' + convert(varchar, [MONTH]) + '.' + convert(varchar, [YEAR]) end
, 104) as CONSDATE,
CONSKG
from
(
select * from CONSUMPTION
) S
unpivot (CONSKG for COLNAME in (DAY1,DAY2,DAY3,DAY4,DAY5,DAY6,DAY7,DAY8,DAY9,DAY10,DAY11,DAY12,DAY13,DAY14,DAY15,DAY16,DAY17,DAY18,DAY19,DAY20,DAY21,DAY22,DAY23,DAY24,DAY25,DAY26,DAY27,DAY28,DAY29,DAY30,DAY31)) as UP;
假设表中没有错误的数据,这不应该失败。
选项3
我能够找到一种方法来使用top
来预防问题。我假设SQL Server无法将where谓词从顶部移到顶部,因为理论上它可以改变结果,即使没有顺序:
select * from (
select top 1000000000 * from CONSUMPTION_CALENDAR
) X
where CONSDATE >= convert(datetime, '20150101')
这似乎工作正常,但无法确定在某些情况下是否会开始失败。