2011-08-11 103 views
5

我修改了客戶現有的查詢,我遇到一個有些莫名其妙的問題失敗。SQL日期時間轉換時,沒有轉換應以地方

我們的客戶使用SQL Server 2008 R2和有關數據庫爲用戶提供了通過利用一個EAV結構的指定其表的一個自定義字段的能力。存儲在該結構中的所有值都是varchar(255),並且其中一些字段用於存儲日期。有問題的查詢將被修改爲使用這些字段中的兩個,並將其與當前日期進行比較(一個是開始,另一個是結束)以確定哪一行是「當前」。

我遇到的問題是該查詢的一部分執行CONVERT(DateTime, eav.Value)以將varchar變爲DateTime。該轉換自己的所有succedd,我可以包括值作爲SELECT條款的一部分,但問題的一部分是給我一個轉換錯誤:

Conversion failed when converting date and/or time from character string. 

真正踢球的是這樣的:如果我定義這個基地查詢(得到實體的名單有變平成單排兩個自定義字段值)作爲視圖,並選擇對視圖和getdate()過濾視圖,然後它工作正常,但如果我添加一個連接到第二失敗表使用視圖中的一個(非日期)字段。我意識到這可能有點難以遵循,所以我可以發佈一個示例查詢,如果需要的話,但這個問題已經變得有點長了。

我試圖重新創建在另一個數據庫的基本結構和包括樣本數據,但新的數據庫的行爲與預期,所以我在虧損就在這裏。

編輯在情況下,它是非常有用的,這裏的視圖的語句:

create view Festival as 
select 
    e.EntityId as FestivalId, 
    e.LookupAs as FestivalName, 
    convert(Date, nvs.Value) as ActivityStart, 
    convert(Date, nve.Value) as ActivityEnd 

from tblEntity e 

left join CustomControl ccs on ccs.ShortName = 'Activity Start Date' 
left join CustomControl cce on cce.ShortName = 'Activity End Date' 
left join tblEntityNameValue nvs on nvs.CustomControlId = ccs.IdCustomControl and nvs.EntityId = e.EntityId 
left join tblEntityNameValue nve on nve.CustomControlId = cce.IdCustomControl and nve.EntityId = e.EntityId 

where e.EntityType = 'Festival' 

發生故障的查詢是這樣的:

select * 

from Festival f 

join FestivalAttendeeAll fa on fa.FestivalId = f.FestivalId 

where getdate() between f.ActivityStart and f.ActivityEnd 

然而,這個工程:

select * 

from Festival f 

where getdate() between f.ActivityStart and f.ActivityEnd 

EntityId/FestivalId ar ËINT列)

+0

可能是由於語言環境,以及美國與非美國格式的日期...檢查語言環境設置...您可以發佈展示該行爲的示例數據嗎? –

+0

也許從第一個失敗併發布的查詢開始。 – Paparazzi

+0

@Mitch:如果我回答的話,那也是我的第一個想法,但這些都是美國的日期,格式可以是'Jan 1 2011 12:00 AM'或'2011/1/1 12:00 AM 」。令人困惑的部分是,錯誤似乎與(根據我的邏輯,顯然可能是錯誤的)不應該影響轉換是否發生。我假設如果數據真的很糟糕,那麼從視圖本身選擇會產生一個錯誤,但事實並非如此。 –

回答

11

我遇到這種類型的錯誤之前,這是由於「操作順序」被執行計劃進行。

您正在收到該錯誤消息,因爲您的語句(由優化程序生成)的執行計劃正在對包含無法轉換爲DATETIME的字符串值的行執行CONVERT()操作。

基本上,你不必在這行優化執行上轉換控制。你知道你只需要在某些行上進行轉換,並且有排除這些行的謂詞(WHERE或ON子句)(將行限制爲需要轉換的行),但執行計劃正在執行CONVERT()操作在行之前排除在外。

(例如,優化器可以被選舉爲做表掃描,並在每一行執行該轉換,被施加任何謂詞之前。)

我不能給出一個明確的答案,而無需生成錯誤的特定問題和特定SQL。


解決此問題的一個簡單方法是使用ISDATE()函數來測試字符串值是否可以轉換爲日期。

也就是說,替換:

CONVERT(DATETIME,eav.Value) 

有:

CASE WHEN ISDATE(eav.Value) > 0 THEN CONVERT(DATETIME, eav.Value) ELSE NULL END 

或:

CONVERT(DATETIME, CASE WHEN ISDATE(eav.Value) > 0 THEN eav.Value ELSE NULL END) 

注意,ISDATE()函數是受到一些顯著的侷限性,如受到會話的DATEFORMAT和LANGUAGE設置的影響。


如果在eav行有其他指示,您可以使用其他測試來有條件地執行轉換。

CASE WHEN eav.ValueIsDateTime=1 THEN CONVERT(DATETIME, eav.Value) ELSE NULL END 

我用另一種方法是嘗試在優化的操作,以獲得控制權的一些點點,使用內聯視圖或公用表表達式,與強制優化操作實現它們並應用謂詞,以便在外部查詢中的任何轉換之前進行。

+0

優秀;這似乎有點顯而易見,現在你提到它是可能的;即使它覺得它應該將這些值視爲視圖的一部分,但它可能決定不這樣做。改變視圖以使用'ISDATE'作爲投影的一部分解決了問題;謝謝! –

+1

+1,但是,對於您的最後一段,請注意[此方法並不總是有效](http://sqlfiddle.com/#!3/0b4c1/1)。 –