Select 基于月份和年份的数据

Select data based on month and year

我们在 Moor.

中按以下格式 2019-10-09T15:29:28.000+08:00 将日期存储为列 created_at 中的字符串

我们想编写一个 select 查询,以检索月份为 10 月且年份为 2019 年的数据。

 Future<ABC> selectReadingBasedOnMonth(
      int month, int year) {
    return (select(abcs)
          ..where((t) {
            final sqliteDate = FunctionCallExpression<DateTime, DateTimeType>(
                'date', [t.createdAt]);

            return sqliteDate.year.equals(year) &
                sqliteDate.month.equals(month);
          }))
        .getSingle();
  }

但是我们没有得到任何数据。这是日志中显示的查询

I/flutter (12004): Moor: Sent SELECT * FROM abcs WHERE (CAST(strftime("%Y", date(created_at), "unixepoch") AS INTEGER)) = ? AND (CAST(strftime("%m", date(created_at), "unixepoch") AS INTEGER)) = ?; with args [2019, 10]

unixepoch 修饰符只能用于 date/time 纯数字的字符串。

The "unixepoch" modifier (11) only works if it immediately follows a timestring in the DDDDDDDDDD format.

This modifier causes the DDDDDDDDDD to be interpreted not as a Julian day number as it normally would be, but as Unix Time - the number of seconds since 1970.

If the "unixepoch" modifier does not follow a timestring of the form DDDDDDDDDD which expresses the number of seconds since 1970 or if other modifiers separate the "unixepoch" modifier from prior DDDDDDDDDD then the behavior is undefined.

For SQLite versions before 3.16.0 (2017-01-02), the "unixepoch" modifier only works for dates between 0000-01-01 00:00:00 and 5352-11-01 10:52:47 (unix times of -62167219200 through 106751991167).

Date And Time Functions

例如考虑以下内容(根据您的查询):-

DROP TABLE IF EXISTS abcs;
CREATE TABLE IF NOT EXISTS abcs (created_at TEXT);
INSERT INTO abcs VALUES ('2019-10-09T15:29:28.000+08:00');

SELECT *, 
    CAST(strftime('%Y', date(created_at)/*, 'unixepoch'*/) AS INTEGER) AS year_nounixepoch,
    CAST(strftime('%m', date(created_at)/*, 'unixepoch'*/) AS INTEGER) AS month_nounixepoch,
    CAST(strftime('%Y', date(created_at), 'unixepoch') AS INTEGER) AS year_invalid,
    CAST(strftime('%m', date(created_at), 'unixepoch') AS INTEGER) AS month_invalid,
    
    CAST(strftime('%Y', strftime('%s',date(created_at)), 'unixepoch') AS INTEGER) AS year_unixepoch,
    CAST(strftime('%m', strftime('%s',date(created_at)), 'unixepoch') AS INTEGER) AS month_unixepoch
    
FROM abcs 
WHERE CAST(strftime('%Y', strftime('%s',date(created_at)), 'unixepoch') AS INTEGER) = 2019 AND CAST(strftime('%m', strftime('%s',date(created_at)), 'unixepoch') AS INTEGER) = 10;
DROP TABLE IF EXISTS abcs; /* cleanup test environment */ 
  • 请注意,单引号已被用来代替双引号,这将是正确的 SQL 尽管这种差异可能是由于消息的输出方式所致。

这导致:-

  • 即在使用 unixepoch 修饰符的地方,它会导致 null,因为 date/time 不仅仅是数字。
  • 选择标准,unixepoch 通过 strftime('%s',..... 按预期工作。

感谢simolus3

提供的answer
 final asDate = FunctionCallExpression('date', [t.createdAt]);
 final year = FunctionCallExpression<String, StringType>(
      'strftime', [const Constant<String, StringType>('%Y'), asDate]);
 final month = FunctionCallExpression<String, StringType>(
      'strftime', [const Constant<String, StringType>('%m'), asDate]);

  return year.equals('2019') & month.equals('07');