Archive

Posts Tagged ‘PostgreSQL’

ビット列型の挙動

CREATE TABLE するときに

foo BIT VARYING(8)
と、しても、

SELECT * FROM t WHERE B'00010000' = foo & B'00010000';
と、すると、

ERROR: cannot AND bit strings of different sizes
などと言われてしまう。

SELECT * FROM t WHERE B'00010000' = foo::bit & B'00010000'::bit;
などとしても同じ。

マニュアルのビット文字列関数と演算子を見てみたら、

単に”bit”にキャストすることは bit(1)にキャストすることを意味することに注意
してください。つまり、単に整数の最下位ビットのみが伝播されることになります。

なんて書いてある。

SELECT * FROM t WHERE B'00010000' = foo::bit(8) & B'00010000'::bit(8);
と、したら、意図するように動いてくれました。

しかし、CREATE TABLE する時に、ビット列データ型ってことも分かっていることだし、桁数だって分かってると思う。文字列で入力しても桁数揃えているんだから、ちゃんと解析して欲しいものです。

しかし、ビット列を主キーにしているテーブルでは、

SELECT * FROM t WHERE foo = foo & b'000100100000';
としても意図する通りに動きました。この差は謎のまま。

時間帯の検索クエリ

設計している DB に時間のデータを絡める必要があったので色々調べてみた。やりたいことは、ある時刻を入力してその時刻に営業している店舗を検索するという感じです。

PostgreSQL には、INTERVAL 型と OVERLAPS 演算子というものがあり、OVERLAPS 演算子はこんなことができるらしい。

SELECT (DATE '2001-02-16', DATE '2001-12-21') OVERLAPS
(DATE '2001-10-30', DATE '2002-10-30');
Result: true

これなら簡単にやりたいことが実現できそうだ、と一瞬感動する。

しかし、よくドキュメントを読んでみると、INTERVAL 型は開始時間と終了時間を入力するとかそういうモノではなく、単純に1時間とか、1日間とか時間幅を受け付けるデータ型らしい。今回は出番はなさそうです。

そして、実際にテーブルを組んでみる。10時は営業時間内か、問い合わせたい場合はこんな感じでしょう。

SELECT * FROM test WHERE (open_time, close_time) OVERLAPS ('10:00', '10:00);

上手く行きました。今度は、日付をまたぐ営業時間(19:00~26:00など)のデータから問い合わせてみます。結果は期待した通りにはなりませんでした。
ググってみたところ、どうやら TIME 型は日付情報を持たないので、開始時間より終了時間が見た目に若いとOVERLAPS が期待する動作をしてくれないらしいそうです。open_time などが TIMESTAMP 型だと勿論そんなことはないです。

結局、下記のようにしました。なんか釈然としない。

SELECT * FROM test WHERE CASE WHEN open_time < close_time THEN
open_time <= '12:00' AND '12:00' <= close_time ELSE
open_time <= '12:00' OR '12:00' <= close_time END;

※今回の教訓
・TIME 型への OVERLAPS は日付けをまたげない。


2005/07/30 13:23 追記

と、思ったらもっとスマートに書けました。WHERE 以降は下記です。

(close_time - open_time)::time >= ('12:00'::time - open_time::interval)