2017-06-09 103 views
3

我有一個頁面,我想運行一些使用ColdFusion和SQL Server數據庫的報告。2個日期之間的查詢記錄

這裏是我的形式:

<cfform name="dateRange" action="" method="POST"> 

    <label>Date From</label><br> 
    <cfinput type="DateField" name="dFrom" mask="DD/MM/YYYY"> 

    <label>Date To</label><br> 
    <cfinput type="DateField" name="dTo" mask="DD/MM/YYYY"> 

    <cfinput type="submit" value="Submit" name="Submit"> 
</cfform> 

<hr> 

<cfif isDefined("form.submit")> 
    <cfinclude template="data-p.cfm"> 
</cfif> 

的數據p.cfm文件看起來像這樣:

<cfset fromDate = #CREATEODBCDATETIME(#form.dFrom#)#> 
<cfset toDate = #CREATEODBCDATETIME(#form.dTo#)#> 

<cfquery name="t"> 
    SELECT id, type, started 
    FROM t_users 
    WHERE started >= #fromDate# 
    AND started <= #toDate# 
    ORDER BY started 
</cfquery> 

<cfdump var="#t#"> 

然而,問題是它轉儲出所有的記錄,並且不應用日期過濾器。當我轉儲查詢時,它會轉儲數據庫中的所有記錄。即使SQL轉儲狀態,它也會忽略WHERE語句:

SELECT id, type, started 
FROM t_users 
WHERE started >= {ts '2017-01-06 00:00:00'} 
AND started <= {ts '2017-08-06 00:00:00'} 
ORDER BY started 

任何想法?

+0

當您執行查詢的轉儲時,它看起來像什麼? – snackboy

+0

當我轉儲查詢時,它會轉儲數據庫中的所有記錄。它忽略了WHERE語句,即使SQL轉儲狀態爲: 'select id,type,start from t_users where started> = {ts'2017-01-06 00:00:00'}並開始<= {ts'2017- 08-06 00:00:00'} ORDER BY started' –

+0

什麼是在結果中返回的範圍之外的'started'值的例子?另外,當你從ssms運行sql時會發生什麼? –

回答

6

它將所有記錄轉儲出來並且不應用日期過濾器。

確實應用日期過濾器。這不是你所期望的。

我懷疑你試圖尋找6月1日之間的記錄 - 6月8日,2017年。然而,如果你在生成的SQL仔細一看,它實際上是在過濾一月6日至8月6日,2017年

where started >= {ts '2017-01-06 00:00:00'} and started <= {ts '2017-08-06 00:00:00'}

的原因是標準CF日期函數只有瞭解美國最新公約,即每月第一。所以當你傳遞一個像「01/06/2017」這樣的字符串時,它將被解釋爲1月 6日 - 而不是6月1日。要正確處理非美國日期字符串,要麼

  • 使用的語言環境敏感的功能,例如LSParseDateTime()(用相應的語言環境)。例如:

    <cfset form.dFrom = "01/06/2017"> 
    <cfset writeDump(LSParseDateTime(form.dFrom, "de_DE"))> 
    
  • 或者對於數字日期,使用ParseDateTime()使用相應的掩碼:

    <cfset form.dFrom = "01/06/2017"> 
    <cfset writeDump(ParseDateTime(form.dFrom, "dd/MM/yyyy"))> 
    

記住CF的日期功能是出了名的慷慨他們認爲有效的日期字符串,所以你可能想添加一些額外的驗證。

另外,出於性能方面的原因,對任何變量查詢參數始終使用cfqueryparam。用於日期比較的更靈活的方法是:

WHERE started >= <cfqueryparam value="#someStartDate#" cfsqltype="cf_sql_date"> 
    AND started < <cfqueryparam value="#dateAdd('d', 1, someEndDate)#" cfsqltype="cf_sql_date"> 
+1

我喜歡那個日期處理。我想這不是我真正想到的,但通常情況下,您會在MS數據庫中使用cf_sql_timestamp。 cf_sql_date截斷時間並將其設置爲午夜,而cf_sql_timestamp包含時間。不到第二天的午夜會在前一天得到你的全部。雖然如果在數據類型精度的邊界處有秒(例如23:59:59.998),那麼可以在第二天結束並排除。檢查數據庫列的數據類型。我之前提到過,但我討厭日期。 – Shawn

+0

@Shawn - 自動截斷是cf_sql_date的優點之一。使構建整個'> = {dayAtMidnight}和<{nextDayAtMidnight}'變得容易。是的,四捨五入很有趣,但是......在這種情況下不確定這是個問題嗎?無論如何,插入/更新時,我認爲舊的日期時間類型auto輪到最近的增量。所以如果你確實使用了像x.998這樣的奇怪值,那麼數據和過濾器都會被舍入到相同的東西,值(最接近的.003或其他)。 – Leigh

+1

我曾經在事務日期時間低至一秒的.xxx的系統中工作。有時令人沮喪。以xx.998進行的交易將整理到第二天,xx.002將下降到一天的開始。所以,雖然從技術上來說xx.998在我尋找的那一天是有效的,但它會在第二天結束並被排除。痛苦。如果您不需要時間,請選擇一個甚至不記錄它的數據庫數據類型。如果你這樣做,確保你有足夠的精度來獲得你所需要的,然後確保你的代碼中使用了正確的數據類型。 : -/ – Shawn

0

進一步編輯。當以data-p.cfm形式包含以下代碼時肯定能夠工作:

<cfset fromDay = listGetAt(form.dFrom, 1, "/")> 
<cfset fromMonth = listGetAt(form.dFrom, 2, "/")> 
<cfset fromYear = listGetAt(form.dFrom, 3, "/")> 
<cfset ToDay = listGetAt(form.dTo, 1, "/")> 
<cfset ToMonth = listGetAt(form.dTo, 2, "/")> 
<cfset ToYear = listGetAt(form.dTo, 3, "/")> 

<cfset fromDate = createdate(fromYear,fromMonth,fromDay)> 
<cfset toDate = createdate(ToYear,ToMonth,ToDay)> 

<cfquery name="t"> 
    SELECT id, type, started 
    FROM t_users 
    WHERE started >= <cfqueryparam value="#fromDate#" cfsqltype="cf_sql_date"> 
    AND started <= <cfqueryparam value="#toDate#" cfsqltype="cf_sql_date"> 
    ORDER BY started 
</cfquery>