SQLite标量函数返回类型总是字符串?

时间:2014-04-23 03:25:46

标签: c# sql sqlite

如果我在没有任何函数的sqlite中选择一个日期类型的列,它会返回一个正确的.NET DateTime对象:

// Returns .NET DateTime object
select date_column from test_table; 

但是当我使用标量函数时,它总是返回string

// Returns string
select datetime(date_column) from test_table; 
select date(date_column) from test_table;

我需要这个的原因是日期舍入

// Rounds to month
select datetime(strftime('%Y-%M-01T00:00:00', date_column)) from test_table;

// Rounds to year
select datetime(strftime('%Y-01-01T00:00:00', date_column)) from test_table;

我尝试实现自己的SQLiteFunction,但它仍然返回一个字符串:

[SQLiteFunction(Name="round_date")]
public class RoundDate : SQLiteFunction
{
    /// <summary>
    /// Expects 2 arguments:
    /// 1: date 
    /// 2: rounding (Month, Quarter, Year)
    /// </summary>
    public override object Invoke(object[] args)
    {
        DateTime date = SQLiteConvert.ToDateTime(args[0].ToString());
        DateTime result = date;
        switch (args[1].ToString())
        {
            case "Month":
                result = new DateTime(date.Year, date.Month, 1);
                break;
            case "Quarter":
                int quarter = (date.Month-1)/3;
                var quarterStart = quarter*3 + 1;
                result = new DateTime(date.Year, quarterStart, 1);
                break;
            case "Year":
                result = new DateTime(date.Year, 1, 1);
                break;
        }

        // function returns a DateTime object.
        // But executing the statement returns a string
        return result;
    }
}

// Uses custom function, but still getting String
select round_date(date_column, 'Year') from test_table;

我知道我可以手动转换/转换字符串结果。

但有没有办法强制select语句自动返回DateTime对象?

[编辑1]

据我所知,Dates和DateTimes不是sqlite中本机支持的数据类型之一。

我也知道我可以手动将格式化的字符串转换为DateTime对象。

但是,select date_column from test_table实际上返回.NET DateTime对象。我假设System.Data.SQLite实现自动执行此转换。

var selectStmt = sqlite.CreateCommand();
selectStmt.CommandText = "select date_column from test_table";
// ==============================
// ==============================
// Returns System.DateTime object
var this_is_a_DateTime_object = selectStmt.ExecuteScalar();
// ==============================

所以当使用date(),datetime()和我自己的SQLiteFunction实现时,我期待这种行为。

4 个答案:

答案 0 :(得分:2)

我不相信有一种方法可以强制System.Data.Sqlite在此实例中为您自动返回.NET DateTime数据类型。这是正在发生的事情。假设您的表定义如下所示:

CREATE TABLE test_table (
    id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    date_column DATETIME NOT NULL
)

正如您已经指出的那样,SQLite中确实没有数据类型。但是,正如您所指出的那样,该库显然正在向您提供本机DateTime值。我的猜测与您的相同:它使用DATETIME的半任意措辞作为您代表您进行此有用转换的请求。

为了测试这个,我在一个DATETIME列中添加了一个明显无效的日期,并且库引发了异常“字符串未被识别为有效的DateTime”。

现在,为了回答你为什么不使用其中一个日期/时间函数获得同样好处的问题,答案在于documentation

  

请注意,所有其他日期和时间函数都可以用strftime()表示:

     

日期(...)strftime('%Y-%m-%d',...)
  时间(...)strftime('%H:%M:%S',......)
  datetime(...)strftime('%Y-%m-%d%H:%M:%S',...)
  julianday(...)strftime('%J',...)

     

提供strftime()以外的功能的唯一原因是为了方便和提高效率。

所以你不是真的调用日期/时间函数。你正在调用一个格式化函数,它的返回时间是 - 你猜对了 - 一个字符串。我尝试将函数的结果转换回日期时间时尝试了一些失败的尝试,如下所示:

select (date(...) as DATETIME), ...

但遗憾的是,您只能使用类型亲缘关系名称(NONE,TEXT,REAL,INTEGER或NUMERIC之一)对SQLite的本机存储类之一进行类型转换。

所以看起来你已经回到了事后必须自己处理转换。 (我也一样。)

答案 1 :(得分:1)

如前所述,您可以为列构建一个DATETIME类型的表,该表在.NET中返回DateTime数据类型。

使用任何内部函数或自定义SQLiteFunction后,它会将其恢复为内部(非日期)数据类型。

如果你真的想要避免String数据类型,可以使用一个有趣的hack,这似乎是我可以强制它在某种程度的日期操作后在.NET中返回DateTime数据类型的唯一方法(至今)。 我自己并不是真的热衷于 ......

如果你定义一个像这样的表......

CREATE Table test2(id bigint, name nvarchar(500), DT datetime)

第三列的查询结果是DateTime。

因此遵循以下逻辑(再次,这是丑陋的,但可能会启发有更多想法的人)将返回由内部日期时间函数修改的日期时间......

CREATE TABLE output (id bigint, name nvarchar, dt datetime)
;
INSERT INTO output
SELECT id, name, DateTime(dt,'+5 years') FROM Test2
;
SELECT * FROM output
;
DROP TABLE output

将此作为单个语句执行将填充一个数据表,其结果为第3列中预期的DateTime数据类型,移位5年。 在您的代码中,如果您可以为每个调用使用唯一的输出表名称,那么该方法可以避免与多个语句发生冲突。

答案 2 :(得分:0)

在SQLite数据库中,&#34;日期和时间&#34;没有存储数据类型。

您可以在SELECT命令之后将数据类型转换为标准.Net DateTime格式。

Query : "SELECT ID, DateModified FROM Customer"
string id = reader.GetInt64(0).ToString();
DateTime dateTime = (DateTime)reader[1];

消息来源:http://techreadme.blogspot.de/2012/11/sqlite-read-write-datetime-values-using.html

抱歉,上述信息适用于SQLite版本1&amp; 2. SQLite3确实包含数据类型,尽管它们的实现方式与标准SQL数据库不同。

https://sqlite.org/datatype3.html

答案 3 :(得分:0)

我不使用SQLite,但是从我读过的内容来看,日期和时间没有原生数据类型。如果您的原始查询正在生成SQLite ADO.NET提供程序将其解释为.NET DateTime值的结果集,那么我只能假设它基于格式。在这种情况下,您可以使用strftime以相同的格式输出,并自动将数据作为DateTime值获取。似乎该格式可能是&#34; yyyy-MM-dd HH:mm:ss.fff&#34;用.NET术语。