gha*_*ndi 4 postgresql perl dbix-class
我只是摆弄了一个复杂的 SQL 查询DBIx::Class(它在幕后用于SQL::AbstractWHERE 子句)。
我使用 BETWEEN 运算符来过滤条目:
# SELECT title FROM tracks WHERE begin BETWEEN '2016-07-01' AND '2016-07-02'
$searchArgs->{'begin'} = { BETWEEN => ['2016-07-01', '2016-07-02' ] };
Run Code Online (Sandbox Code Playgroud)
这将跳过实际的开始日期 2016-07-02。可能是因为这些开始值已超过 2016 年 7 月 2 日午夜 (00:00),因此不在 BETWEEN 范围内(请参阅末尾的示例数据)。
在 SQL 端,这个问题很容易修复:
SELECT title FROM tracks WHERE DATE(begin) BETWEEN '2016-07-01' AND '2016-07-02'
# Note the DATE()-cast of begin
Run Code Online (Sandbox Code Playgroud)
有没有办法通过SQL::Abstract语法来实现这一点?我尝试将列名称作为标量引用($searchArgs->{\"DATE(begin)"})以使其不受影响地通过,但没有成功。
$searchArgs->{'DATE(begin)'}由于没有这样的列“DATE(begin)”,因此仅使用就会触发 SQL 错误。
# Minimal example data
CREATE TABLE test ( title VARCHAR(255), begin timestamp );
INSERT INTO test (title, begin) VALUES ( 'Track 1', '2016-07-01T12:00:00'::timestamp), ( 'Track 2', '2016-07-02 12:00:00'::timestamp );
SELECT title FROM test WHERE begin BETWEEN '2016-07-01' AND '2016-07-02';
SELECT title FROM test WHERE DATE(begin) BETWEEN '2016-07-01' AND '2016-07-02';
Run Code Online (Sandbox Code Playgroud)
问题似乎是像这样的日期'2016-07-02'相当于'2016-07-02T00:00:00', 且'2016-07-02T12:00:00'大于该日期。调用DATE()只是截断时间值,以便丢弃额外的十二个小时
我建议您放弃BETWEEN, 并使用等效的>=和<=运算符。您实际上想要所有记录,但不包括 '2016-07-03T0:00:00'(即,所有记录,包括在内,2016-07-02T23:59:59以及您的数据库可能支持的任何几分之一秒),因此您应该编写
SELECT title FROM test
WHERE begin BETWEEN >= '2016-07-01' AND begin < '2016-07-03';
Run Code Online (Sandbox Code Playgroud)
或者,在DBIx::Class
$searchArgs->{begin} = {
'>=' => '2016-07-01',
'<' => '2016-07-03',
};
Run Code Online (Sandbox Code Playgroud)
或者,如果您只能访问结束日期并且希望避免 Perl 代码中的日期算术,那么只需让数据库为您完成即可
$searchArgs->{begin} = {
'>=' => '2016-07-01',
'<' => \[ 'date(?) + 1', '2016-07-02' ],
};
Run Code Online (Sandbox Code Playgroud)
如果您坚持在 WHERE 比较中使用函数而不是简单的表名,那么可以使用文字 SQL,但这是不可取的,因为您将绕过数据库可以提供的所有优化,并且必须诉诸线性搜索
该文档在比较左侧的“使用 SQL 函数”DBIx::Class::Manual::Cookbook下有此内容
在比较的左侧使用 SQL 函数通常不是一个好主意,因为它需要扫描整个表。(除非您的 RDBMS 支持表达式索引 - 包括函数的返回值 - 并且您在相关函数的返回值上创建索引。)但是,必要时可以通过诉诸
DBIx::Class文字 SQL来完成