シェルから,psql abc xyzというコマンドで,データベースabcに,ユーザxyzとして接続するとします.そして,「select user;」と「select usr;」を問い合わせると,結果は次のようになります.
xyz=> select user; current_user -------------- xyz (1 行) xyz=> select usr; ERROR: 列"usr"は存在しません 行 1: select usr; ^
ここで出るuserは,現在実行しているユーザ名を返す関数であり,current_userと同じであることが,ここやここに書かれています.
困ったことに,データベースabcの中で定義している,テーブルresultsの中に,userという名前の属性があります.定義したときは問題にならなかったのですが,SELECTの際に
xyz=> select * from results where user='takehikom';
としても,レコードが得られません.かわりに
xyz=> select * from results where results.user='takehikom';
とする必要があります.
さて,resultsと複数形のテーブル名にしていることから,感づく方もいらっしゃると思いますが,テーブルはRuby + ActiveRecordで定義し,また問い合わせもそこから行っています.次のRubyのコードは,不具合なく動きます.
array = Result.find(:all, :conditions => {:user => "takehikom"}, :order => "start_at DESC")
start_atというのは,これもresultsテーブルの中で定義している属性名で,開始日時を格納しています.ここで,userがtakehikomで,かつ,start_atが今年の4月1日以降のものを取り出したいと考えました.まずは,こう.
user = "takehikom" start_at = "2010-04-01" array = Result.find(:all, :conditions => ["user=? and start_at>=?", user, start_at], :order => "start_at DESC")
しかし,これでは取得できません.ここのuserが,冒頭に書いた関数になってしまったようです.次に,arrayへの代入のところを
array = Result.find(:all, :conditions => ["?.user=? and start_at>=?", Result.table_name, user, start_at], :order => "start_at DESC")
としたらどうかというと,Rubyの実行時エラーとなりました.エラーメッセージを見ると…
RuntimeError: ERROR C42601 M"."またはその近辺で構文エラー P43 Fscan.l L907 Rbase_yyerror: SELECT * FROM "results" WHERE ('results'.user='takehikom' and start_at>='2010-04-01') ORDER BY start_at DESC (ActiveRecord::StatementInvalid)
「'results'.user」って変ですね.「results.user」でないと,いけません.psqlから,
xyz=> SELECT * FROM "results" WHERE ('results'.user='takehikom' and start_at>='2010-04-01') ORDER BY start_at DESC;
ではうまくいかず,
xyz=> SELECT * FROM "results" WHERE (results.user='takehikom' and start_at>='2010-04-01') ORDER BY start_at DESC;
だと大丈夫なのを確認しました.
さてどうしますか…プレースホルダで実現するのは無理そうなので,
array = Result.find(:all, :conditions => ["#{Result.table_name}.user=? and start_at>=?", user, start_at], :order => "start_at DESC")
として,解決しました.
結局のところ,テーブル名,属性名を割り当てるときに,SQLのキーワード,関数名,システムカタログの名前*1などと同じにしないよう,配慮しないといけませんね….
関連:
*1:http://www.postgresql.jp/document/8.4/html/catalogs.htmlを見たところ,すべて「pg_」から始まっているので,バッティングする可能性はまずないでしょう.いや,何か作るときに,しでかすかも….