@kyanny's blog

人間が神のしくじりなのか、神が人間のしくじりなのか、どっちだ - ニーチェ ドイツ哲学者

PostgreSQL: psql に -c で SQL を実行させる場合とパイプから SQL を実行させる場合の -v オプションの扱いの違い

パイプから SQL を入力して実行させる場合は -v オプションで指定した変数が展開される。

echo "select * from pg_catalog.pg_attrdef where oid=:oid" | psql -U postgres -h localhost -p 5432 -d postgres --csv -v oid=473051
oid,adrelid,adnum,adbin
473051,473048,1,{FUNCEXPR :funcid 480 :funcresulttype 23 :funcretset false :funcvariadic false :funcformat 2 :funccollid 0 :inputcollid 0 :args ({FUNCEXPR :funcid 1574 :funcresulttype 20 :funcretset false :funcvariadic false :funcformat 0 :funccollid 0 :inputcollid 0 :args ({CONST :consttype 2205 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ -42 55 7 0 0 0 0 0 ]}) :location -1}) :location -1}

-c (--command) で SQL を実行させる場合は -v オプションで指定した変数は展開されず syntax error になる。

$ psql -U postgres -h localhost -p 5432 -d postgres --csv -v oid=473051 -c "select * from pg_catalog.pg_attrdef where oid=:oid"
ERROR:  syntax error at or near ":"
LINE 1: select * from pg_catalog.pg_attrdef where oid=:oid

これはおそらく -c オプションの制約によるもの。

commandは、サーバで完全に解析可能な(つまり、psql特有の機能は含まない)コマンド文字列、もしくは、バックスラッシュコマンド1つである必要があります。 このため、-cオプション内ではSQLとpsqlメタコマンドを混在させることはできません。 これらを同時に使用するには、-cオプションを繰り返し利用するか、あるいはパイプを使って文字列をpsqlに渡します。 例えば、

https://www.postgresql.jp/document/12/html/app-psql.html

-v オプションは psql 特有の機能であるため、 PostgreSQL サーバで完全に解析可能ではない、ということなのだろう。 syntax error になるのもうなずける。


WHERE 句が可変な SQL をシェルからワンライナーで実行したい、というような場合は、パイプ + 変数でやるか、あらかじめシェルスクリプトか別のスクリプト言語などで可変部分を埋め込んだ SQL を組み立てておき、パイプで psql に渡すのが良さそう。