Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 当日期用作条件时,视图中的Unpivot会导致转换为日期的错误_Sql Server_Sql Server 2008_Unpivot - Fatal编程技术网

Sql server 当日期用作条件时,视图中的Unpivot会导致转换为日期的错误

Sql server 当日期用作条件时,视图中的Unpivot会导致转换为日期的错误,sql-server,sql-server-2008,unpivot,Sql Server,Sql Server 2008,Unpivot,我有一个表,每个月有一行,金额存储在不同的列中(第1天、第2天……第31天)。我创建了一个视图,该视图使用unpivot每天将其拆分为一行,这样我就可以对给定的日期范围进行计算 当我试图通过只选择某个日期范围来使用视图时,只要表中有DAY29..DAY31,它就会出错。如果该表最多只包含28天,那么它可以正常工作 不幸的是,更改表结构并不是一个真正的选项,我用内联函数尝试了同样的方法,但最终还是出现了同样的错误 Msg 242,16级,状态3,第52行nvarchar数据的转换 类型转换为日期时

我有一个表,每个月有一行,金额存储在不同的列中(第1天、第2天……第31天)。我创建了一个视图,该视图使用unpivot每天将其拆分为一行,这样我就可以对给定的日期范围进行计算

当我试图通过只选择某个日期范围来使用视图时,只要表中有DAY29..DAY31,它就会出错。如果该表最多只包含28天,那么它可以正常工作

不幸的是,更改表结构并不是一个真正的选项,我用内联函数尝试了同样的方法,但最终还是出现了同样的错误

Msg 242,16级,状态3,第52行nvarchar数据的转换 类型转换为日期时间数据类型导致值超出范围

这是我的桌子:

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'
是否有任何变通办法,我可以选择某个日期范围

编辑:视图中的数据:

ID          YEAR        MONTH       CONSDATE      CONSKG
1           2015        1           2015-01-01    10
1           2015        1           2015-01-02    20
1           2015        1           2015-01-03    30
1           2015        1           2015-01-31   310
1           2015        2           2015-02-01    10
1           2015        2           2015-02-02    20
1           2015        2           2015-02-03    30

选项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
日历表的日期格式为
D.M.YYYY
,在DATESTR中没有前导零,日历日期为
Date

选项2

当空值更改为1.1.1900时,对于这样的视图,提取似乎也可以正常工作:

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')

这似乎可以,但不能确定在某些情况下是否会失败。

改变结构是不可能的吗?这个数据的“自然”表示形式是未填充的表单,为什么不这样存储?你能在视图(消费日历)中发布一个数据示例吗?这个表在很多地方使用,当然不止一个,所以我真的不想碰它。还为@haytemIt添加了日历格式的数据,它在Fiddle中运行良好,您可以尝试以下两个查询:select*from CONSDATE>=convert(datetime,'20150101');从消费日历中选择*,其中convert(datetime,CONSDATE)>='20150101'@haytem这两个选项在我的小提琴中都失败了。它将获取数据,但它也失败了:我会非常小心依赖它。SQLServer可以移动谓词,甚至可以移动到超出SQL标准允许的范围。一些测试可能表明,这目前“有效”,但几乎任何事情都可能导致服务器在未来生成一个不同的计划,而错误会再次出现(例如,可用内存、表中数据、统计数据、索引的更改都可能导致计划的更改)@Damien_不相信者我也担心这一点。现在我找到了另一种方法,将所有空值更改为固定日期,这听起来应该是可行的,因为无效日期不能有数字。