4

私の質問は、実際には私の究極の目的です。これまでのところ、2つの問題があります。

  1. アラビア語の日付をmysqlの「日付」として保存するには? なぜなら、私はグレゴリオ暦をイスラム暦に変換してから、preg_replace (php、今のところ、最終は Java にあります) を使用すると、数字がアラビア語の 16 進法に変更され、MySQL に varchar として保存されるためです。

アラビア語で保存できる照合 cp1256_general_ci については知っていますが、現在のところ、簡単にするために脇に置いています。utf-8_general も問題なく動作しています。したがって、varchar として保存することは問題ではなく、「date」として保存することは問題です。

  1. それに対してクエリを実行します。要件はそこで終わると思っていましたが、現在のタスクは、日付のようなクエリを実行することですxyzとpqrの間で...また、制約は「アラビア語のみで保存する」ことです。

どんな入力でも大歓迎です。

4

2 に答える 2

3

SQLの日付

私はそれを次のように考えます:サーバーは実際には特定の日の参照として日付を保存します。それがどのように行われるかはあなたの関心事ではありません。このような日付列にデータを格納したり、そのような日付列からデータを読み取ったりする場合、サーバーは特定のカレンダーを使用してその日付を表します。これは慣例によりグレゴリオ暦です。私が言おうとしているのは、保存された値がグレゴリオ暦であるとは思わないということです。むしろ、移管された日付はグレゴリオ暦であると考えたいと思います。

したがって、私の意見では、最善の解決策は、その事実を受け入れ、アプリケーション側でグレゴリオ暦とイスラム暦の間で変換することです。そうすれば、通常のbetweenチェックを使用できます。

数字で構成された文字列

ロケールに依存する変換が複雑すぎるため、またはイスラム暦とグロゴリアンの間のマッピングが一意でないか事前に不明であるためにこれが不可能な場合は、日付を別の形式で保存する必要があります。私の頭に浮かぶ可能性のある形式は、数字を意味する文字をvarchar含む形式の文字列を含むものです。YYYY-MM-DDこのスキームにより、文字列がそれらが表す日付のように比較されることが保証されるため、文字列で引き続き使用できbetweenます。ただし、これらの文字列をスペルアウトされた日付に戻すのは難しいでしょう。

1つ以上の数値列

したがって、実際には3つの列を使用することをお勧めします。各列には日付を示す数値が含まれています。次に、を使用10000*year + 100*month + day_of_monthして、比較やに使用できる、毎日1つの数値を取得できますbetween。一方、ELTクエリでこの関数を使用すると、その月の数値を名前に戻すことができます。パフォーマンスが問題になる場合は、1つの数値だけを保存し、選択時にそれを部分に分割する方がよい場合があります。グレゴリオ暦では、これは次のようになります。

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、月の名前を数値に変換することです。データベースにトリガーを追加すると、文字列が常に有効な形式になり、この方法で分解できるようになります。この質問では、トリガーを使用してそのようなチェックを実施する方法について詳しく説明します。

于 2012-10-22T05:24:17.810 に答える
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 ;
于 2013-11-22T06:18:12.360 に答える