SQL 日期
我会这样想:服务器实际上将日期存储为对给定日期的引用。它是如何做到的与您无关。在将数据存储到此类日期列或从此类日期列读取数据时,服务器使用特定日历表示该日期,按照惯例,该日历是公历。我想说的是,我不会认为存储的值是公历的,尽管它很可能是。我宁愿认为转移日期是公历。
因此,在我看来,最好的解决方案是接受这一事实并在应用程序端在 Gregorian 和 Hijri 之间进行转换。这样,您可以between
对其使用常规检查。
由数字组成的字符串
如果这是不可能的,因为依赖于语言环境的转换太复杂,或者因为回历和 Grogorian 之间的映射不是唯一的或事先不知道,那么您将不得不以其他形式存储日期。我想到的可能形式是varchar
包含形式的字符串YYYY-MM-DD
,其中字母表示数字。此方案确保字符串会像它们所代表的日期一样进行比较,因此您仍然可以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;
兼容性和便利性
如果您必须保持与需要单个文本日期列的代码的只读兼容性,您可以使用 aVIEW
来提供它。例如,对于德语 GregorianDD. 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
月份名称转换为数字。您可能希望向数据库添加一个触发器,以确保您的字符串始终采用您可以通过这种方式分解的有效格式。这个问题详细介绍了如何使用触发器来强制执行此类检查。