2016-07-04 14 views
2

DBIx::Classで生成された複雑なSQLクエリ(WHERE句にはSQL::Abstractを使用)を使用していました。DBIx :: Class/SQL :: Abstract WHERE節のカラムにSQL関数を適用する

私は、エントリをフィルタするためにオペレータBETWEEN使用しています:

# SELECT title FROM tracks WHERE begin BETWEEN '2016-07-01' AND '2016-07-02' 
$searchArgs->{'begin'} = { BETWEEN => ['2016-07-01', '2016-07-02' ] }; 

は、この実際に2016年7月2日から始まり、日付をスキップします。おそらく、これらの開始値は2016-07-02の真夜中(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 

SQL::Abstract構文でこれを達成する方法はありますか?私はスカラー・リファレンス($searchArgs->{\"DATE(begin)"})として列名を試して、手を加えずに通過させましたが、うまくいきませんでした。

ちょうど$searchArgs->{'DATE(begin)'}を使用すると、「DATE(開始)」という列が存在しないため、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'; 
+0

「*動作していません」という意味ですか? – Borodin

+0

DATE() - Functionを列側で取得する方法が見つかりませんでした。 – ghandi

+0

確かに、あなたが試したとき何が起こったのですか? – Borodin

答えて

3

問題が'2016-07-02'のような日が'2016-07-02T00:00:00'と等価であることのようだ、と'2016-07-02T12:00:00'はより大きいです。余分に12時間は

を破棄されるように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'; 
DBIx::Class

か、を記述する必要があります含めない

$searchArgs->{begin} = { 
    '>=' => '2016-07-01', 
    '<' => '2016-07-03', 
}; 

または終了日のみへのアクセス権を持っているし、あなたのPerlコードで日付の計算を避けたいならば、単にデータベースはあなた

のためにそれをやらせます



あなたの比較が、それはリテラルSQLを使用することにより可能であるに単純なテーブル名の代わりに関数を使用することを主張していますが、そのデータベースのすべての最適化をバイパスしますと、それはお勧めできませんなら提供することができ、それがUsing SQL functions on the left hand side of a comparison

Uの下で線形検索DBIx::Class::Manual::Cookbookドキュメントは、これを持っている

に頼らなければならないでしょう比較の左側のSQL関数を呼び出すことは、テーブル全体をスキャンする必要があるため、一般的には良い考えではありません。 (RDBMSが関数の戻り値を含む式の索引をサポートしていない場合は、問題の関数の戻り値に索引を作成します。しかし、必要に応じてリテラルSQLに頼ってDBIx::Classで実現できます

+0

あなたの解は、ある日の数学(2016-07-31 + 1日=> 2016-08-01)を意味します。現実のクエリは後で動的に実行されます。それ以外にも、それはうまくいくだろう(しかし、BETWEENと同じ)。しかしおそらくそれはもうDBIx :: Class/SQL :: Abstract問題ではありません。言及された制限で私はそれが見えるようにさらにresaerchする必要があります... – ghandi

+0

@ガンディー:さて、ちょうど算術演算を行うためにいくつかの明示的なSQLを使用してください。 '' <' => \ ['date(?)+ 1'、 '2016-07-02'] 'はうまく動作するはずですが、テストしていません。あなたは本当に解決策があまり合わないと沈黙してはいけません。それを改善する方法がわからないから – Borodin

+0

いいえ、ちょうどオンラインではありませんでした。 ;) 'date(...)+ 1'は良い回避策ではありません。ありがとう:) – ghandi

関連する問題