2016-01-26 21 views
-1

我有了每月一行和量被存儲在不同的列(DAY1,DAY2 ... DAY31)的表。我創建了一個視圖,使用unpivot將其分割成每天一行,以便我可以對給定的日期範圍進行計算。逆透視鑑於導致誤差轉化成日期時以此爲標準日期

當嘗試通過僅選擇特定日期範圍要使用的視圖,它在錯誤只要當我在表DAY29..DAY31結束。如果表格只包含28天的日期,那麼它工作正常。

不幸的是改變表的結構是不是一個真正的選擇,我試圖用內聯函數相同的事情,但在相同的錯誤最終

消息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 

實施例SQL Fiddle

+0

正在改變結構出來的問題?這個數據的「自然」表示是未轉換的形式,爲什麼它不是這樣存儲的? –

+0

您可以在視圖中發佈數據示例(CONSUMPTION_CALENDAR)嗎? –

+0

這張桌子在很多地方都有使用,當然還有不止一種,所以我不太想去碰它。在日曆格式中添加@haytem的數據 –

回答

1

選項1

創建具有日期在合適的格式的日曆表中,例如D.M.YYYY可以與unpivot連接。這種方式沒有從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前導零和CALENDARDATE是Date

選項2

的獲取似乎與視圖這樣的,當空值改爲1900年1月1日確定也正常工作:

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是無法在那裏謂語從外上方移動到它,因爲在理論上它可以改變結果,即使是沒有訂單:

select * from (
    select top 1000000000 * from CONSUMPTION_CALENDAR 
) X 
where CONSDATE >= convert(datetime, '20150101') 

這似乎是工作確定,但可以不確定在某些情況下這是否會失敗。

+0

我會非常警惕*依賴*。 SQL Server *可以*移動謂詞,甚至超出SQL標準所允許的範圍。一些測試可能表明,這種方法目前「有效」,但幾乎任何事情都可能導致服務器在將來出現錯誤時產生不同的計劃(例如,可用內存,表中數據,統計數據,索引等方面的變化都可能導致改變計劃) –

+0

@Damien_The_Unbeliever這也是我害怕的。現在我想通過將所有NULL值更改爲固定日期來找到另一種方式,這對我來說聽起來應該起作用,因爲無效日期不能有數字。 –