2012-10-22 25 views
4

我的問題實際上是我的最終目標。 到目前爲止,我有2個問題。如何在阿拉伯語(hijri)日曆中執行'between'並將其保存爲'date'在MySQL中?

  1. 如何將阿拉伯語日期保存爲mysql中的'date'? 因爲我已經將Gregorian轉換爲Hijri,然後使用preg_replace(php,現在,final在Java中)將數字更改爲阿拉伯語ascii hex ...然後將它作爲varchar保存在MySQL中。

我知道排序規則cp1256_general_ci,它允許我們以阿拉伯語存儲,但是,目前爲了簡單起見,我已經放在一邊。 utf-8_general也很好。所以存儲爲varchar不是問題,存儲爲'date'。

  1. 對其執行查詢。 我認爲需求會在那裏結束,但是,現在的任務是執行諸如'xyz和pqr之間的日期'之類的查詢......此外,約束條件是「僅以阿拉伯語存儲」。

任何輸入,非常感謝。

+0

STR_TO_DATE()的MySQL函數可以used.may是性能下降 –

+0

感謝@ArunKillu,試了一下,沒有工作。性能對我們來說不是問題。我們可以隨時調整它,但現在,str_to_date只會將字符串轉換爲日期,但這並不意味着mysql的'date'將允許我將它作爲日期存儲。試過了,沒有工作。因爲,MySQL假設「日期」中的任何內容都必須是僅有英文的數字。 – Karma

+0

可以用英文存儲日期,然後在檢索後將其轉換爲阿拉伯文。 –

回答

3

SQL日期

我想它是這樣的:服務器實際存儲的日期爲某一天的參考。它怎麼做,這不關你的事。將數據存儲到日期列或從日期列讀取數據時,服務器使用特定的日曆來表示該日期,該日曆按照慣例是格雷戈裏。我想說的是,我不認爲存儲的價值是格雷戈裏,雖然它可能是。我寧願考慮轉讓日期爲格雷戈裏。

因此,在我看來,最好的解決方案是接受這一事實,並在應用程序方面轉換格里高利和Hijri。這樣,你可以使用正常的between檢查。從數字

如果這是不可能由

字符串,由於該區域設置相關的轉換太複雜了,還是因爲愨回曆和Grogorian映射不是唯一的或者事先不知道的,那麼你將不得不以其他形式存儲日期。我想到的可能的形式是包含YYYY-MM-DD形式的字符串的varchar,其中字母表示數字。這種方案可以確保字符串與其所代表的日期相比較,因此您仍然可以使用between。儘管如此,將這些字符串轉換爲拼寫出來的日期仍然很棘手。

一個或多個數字列

所以我真的建議你使用三列,每個包含數標誌着一個日期,然後,您可以使用10000*year + 100*month + day_of_month獲得每一天的單號,你可以使用進行比較和between。另一方面,您可以在查詢中使用功能ELT將該月份的號碼恢復爲名稱。如果性能問題,您可能會更好地存儲一個數字,並在選擇時將其分成若干部分。在公曆,這應該是這樣的:

CREATE TABLE tableName (myDate DECIMAL(8)); 

SELECT myDate DIV 10000 AS year, 
     ELT((myDate DIV 100) MOD 100, "Jan", "Feb", …) AS month, 
     myDate MOD 100 AS day_of_month 
FROM tableName 
WHERE myDate BETWEN 20121021 AND 20121023; 

兼容性和方便

如果你要保持只讀與代碼,只需要一個文本日期列的兼容性,您可以使用VIEW提供。例如,對於德國公曆DD. MMMM YYYY格式,你可以使用這樣的代碼:

CREATE VIEW compatibleName AS 
SELECT CONCAT(myDate MOD 100, ". ", 
       ELT((myDate DIV 100) MOD 100, "Januar", "Februar", …), ". ", 
       myDate DIV 10000) as dateString, 
     * -- or explicitely name other columns needed for compatibility 
FROM tableName 

解碼串

如果你需要使用字符串格式讀寫被其他應用程序的訪問,你必須解析那些絃樂自己。您可以在SQL級別執行此操作。有用的工具是SUBSTRING_INDEX將字符串拆分爲字段並FIELD將月份名稱轉換爲數字。您可能需要向數據庫添加觸發器,以確保您的字符串始終處於可以以這種方式分解的有效格式。 This question給出瞭如何使用觸發器來執行這些檢查的詳細信息。

+0

+1在同一軌道上。但是,另一個後端提供程序將在應用程序中顯示爲「原樣」,因此要求僅將其存儲在阿拉伯語中。由於用戶「被假設」僅接受了解阿拉伯語的教育。 – Karma

+0

@KarmicDice,你是什麼意思的「其他後端提供者」?你的控制之外的其他一些代碼訪問同一個表?它是否也會寫入表格,或只讀取它?如果它只是讀取權限,那麼你可以根據你的表格建立一個[view](http://dev.mysql.com/doc/refman/5.6/en/create-view.html),它將顯示日期用阿拉伯語寫成。如果數據真的必須以阿拉伯語存儲,那麼您必須在SQL中使用'SUBSTRING_INDEX'來拆分日期和'FIELD'以識別月份的名稱,從而將字符串轉換爲數字。 – MvG

+0

真棒! @MvG它完全有道理!謝謝。請用評論編輯(修改)您的答案。我會接受它。我的合作開發者也對你的迴應感到好笑。再次感謝。 – Karma

3

您可以直接存儲爲日期。我是正常的約會。我的MySQL功能

DELIMITER $$ 

DROP FUNCTION IF EXISTS `kdmtest`.`IntPart` $$ 
CREATE FUNCTION `kdmtest`.`IntPart` (FloatNum float) RETURNS INT 
BEGIN 
if (floatNum< -0.0000001) then 
    return ceil(floatNum-0.0000001); 
else 
    return floor(floatNum+0.0000001); 
end if; 
END $$ 

DELIMITER ; 


DELIMITER $$ 

DROP FUNCTION IF EXISTS `kdmtest`.`Hicri` $$ 
CREATE DEFINER=`root`@`localhost` FUNCTION `Hicri`(MiladiTarih date) RETURNS date 
BEGIN 
    declare d,m,y,jd,l,n,j int; 
    set d=day(MiladiTarih); 
    set m=month(MiladiTarih); 
    set y=year(MiladiTarih); 
    if ((y>1582) or((y=1582) and (m>10)) or ((y=1582) and (m=10) and (d>14))) then 
    set jd=intpart((1461*(y+4800+intpart((m-14)/12)))/4)+intpart((367*(m-2-12*(intpart((m-14)/12))))/12)- intpart((3* (intpart( (y+4900+ intpart((m-14)/12) )/100) ) ) /4)+d-32075; 
    else 
    set jd = 367*y-intpart((7*(y+5001+intpart((m-9)/7)))/4)+intpart((275*m)/9)+d+1729777; 
    end if; 
        set l=jd-1948440+10632; 
        set n=intpart((l-1)/10631); 
        set l=l-10631*n+354; 
        set j=(intpart((10985-l)/5316))*(intpart((50*l)/17719))+(intpart(l/5670))*(intpart((43*l)/15238)); 
        set l=l-(intpart((30-j)/15))*(intpart((17719*j)/50))-(intpart(j/16))*(intpart((15238*j)/43))+29; 
        set m=intpart((24*l)/709); 
        set d=l-intpart((709*m)/24); 
        set y=30*n+j-30; 
return concat(y,'-',m,'-',d); 
END $$ 

DELIMITER ; 


DELIMITER $$ 

DROP FUNCTION IF EXISTS `kdmtest`.`Miladi` $$ 
CREATE FUNCTION `kdmtest`.`Miladi` (HicriTarih date) RETURNS date 
BEGIN 
    declare d,m,y,jd,l,n,j,i,k int; 
    set d=day(HicriTarih); 
    set m=month(HicriTarih); 
    set y=year(HicriTarih); 
    set jd=intPart((11*y+3)/30)+354*y+30*m-intPart((m-1)/2)+d+1948440-385; 
    if (jd> 2299160) then 
     set l=jd+68569; 
     set n=intPart((4*l)/146097); 
    set l=l-intPart((146097*n+3)/4); 
     set i=intPart((4000*(l+1))/1461001); 
    set l=l-intPart((1461*i)/4)+31; 
    set j=intPart((80*l)/2447); 
    set d=l-intPart((2447*j)/80); 
     set l=intPart(j/11); 
     set m=j+2-12*l; 
     set y=100*(n-49)+i+l; 
    else 
    set j=jd+1402; 
    set k=intPart((j-1)/1461); 
    set l=j-1461*k; 
    set n=intPart((l-1)/365)-intPart(l/1461); 
    set i=l-365*n+30; 
     set j=intPart((80*i)/2447); 
     set d=i-intPart((2447*j)/80); 
     set i=intPart(j/11); 
     set m=j+2-12*i; 
     set y=4*k+n+i-4716; 
    end if; 
    return concat(y,'-',m,'-',d); 
END $$ 

DELIMITER ; 
相關問題