Csvファイルに書き込むために試行錯誤している複数のクエリを含むスクリプトがあります。
copy (
select /* very long query */
) to '/tmp/report.csv' with csv header;
そして、私はこのようなスクリプトを実行します
psql -d mydb -f produce_reports.sql
スクリプトは機能しているようですが、/ tmpには何も書き込まれていません。
通常は\copy
を使用しますが、スクリプトではこれを使用できません。私が\copy
を使用して理解していることから、すべてのコマンドを同じ行に置く必要がありますが、これは私にとって実行可能なオプションではありません。
COPYが成功を報告するが、何も書き込まない理由
P.SはSudoとPSQLを使用してrunnigを試行し、mydbユーザーにスーパーユーザーを許可しようとしました。
通常は
\copy
を使用しますが、スクリプトではこれを使用できません。私が\copy
を使用して理解していることから、すべてのコマンドを同じ行に置く必要がありますが、これは私にとって実行可能なオプションではありません。
すべてのコマンドが同じ行にある必要はありませんが、ここでは問題ではありません。 COPY
はファイルを保存していますサーバー上。あなたはそれをクライアント上で望みます、それはpsqlコマンド\COPY
がすることです。ファイルがある場所であるリモートサーバーに接続していると思います。おそらくscp
またはrsync
をクライアントなどに返すことができますが、それは悪い考えです。あなたはクライアントだけでそれを行う方が良いです。
\copy
を別の行に配置する方法は多数あります。たとえば、これを取りなさいtest.psql
CREATE TEMP TABLE t AS VALUES (1,2), (2,3);
\COPY t TO /tmp/1
CREATE TEMP TABLE b AS VALUES (1,2), (2,3);
\COPY t TO /tmp/2
psql -d test -f test.psql
で実行できます
COPY
は、SQLのように見えるように作成されたPostgreSQLサーバーコマンドです。\COPY
はCOPY
のように作成されたPostgreSQLクライアント(psql)コマンドですpsql -c
オプションを使用します。
[pol@UNKNOWN ~]$ psql --version
psql (PostgreSQL) 10.1
次のようなコマンドを実行できます。
> psql -c 'SELECT * FROM bank_account;' test > bank_details.txt
(私はtest
というデータベースを持っています)そして次に:
> more bank_details.txt
それは与える:
account_id | first_name | last_name | address_number | address_street1 | address_street2 | address_town | address_county | balance
------------+------------+---------------+----------------+---------------------------------+---------------------------------+---------------------------------+----------------+---------
1 | 83fbc | 613f37db7f46 | 65 | a91fd | af5aae2642a7f418c306da | 02 | Dublin | 668
2 | cbca6 | c36eabe7b07f | 28 | 295301 | 45f260962b7eed | b4bdf5a03bf6ab | Dublin | 438
3 | 62a47 | 9ca84de | 66 | c7bdbafb606d5bd605e8254 | c6d2a6104f457f2 | ce8c579526c009ee50fd6c728da363 | Dublin | 358
4 | 371e | 27ce5752d5 | 21 | ec2401c9db6 | ed7d8a1507a | 1bcef72a619e7239215a | Dublin | 730
5 | 70bb6 | a767ad3 | 6 | fe76de803945b87a01aebded | 708193a5484239284fb15cf68d5d5 | 67face4e59f38f793ab10c5 | Dublin | 785
(実際のデータではない-言うまでもなく:-))
編集:
ここで、いくつかのコマンドを順番に実行して、さまざまなファイルにデータを書き込む場合は、次のようにする必要があります。
スクリプトファイルpg.sh
-chmod 755
を作成します。
[pol@UNKNOWN pgtest]$ more pg.sh
psql -c "\o mydata.txt" -c "SELECT * FROM bank_account;" -d test
psql -c "CREATE TABLE mytest(f1 INTEGER, f2 VARCHAR (50));" -d test
psql -c "INSERT INTO mytest VALUES (34, 'First record test...');" -d test
psql -c "INSERT INTO mytest VALUES (36, 'Second record test' );" -d test
psql -c "\o another_file.txt" -c "SELECT * FROM mytest;" -d test
psql -c "\i /home/pol/pgtest/test.sql" -d test
[pol@UNKNOWN pgtest]$
その後、単に
> ./pg.sh
そして、2つの新しいファイル-mydata.txtとデータを含むanother_file.txtがあります!さらに、あなたは時間の間に操作を実行しました!
また、さらに別のSQLスクリプト-test.sqlを入力します-以下を参照してください。
Test.sqlというファイルも作成しました
[pol@UNKNOWN pgtest]$ more test.sql
SELECT * FROM bank_account;
SELECT * FROM mytest;
そして、これを使用して実行します
psql -f sql.sh -d test
選択したファイルにリダイレクトできます!または、上記のように別のインサイダーからこのスクリプトを実行します!
PostgreSQLのマニュアルページをよく読むこともできます(これは優れています!) here :
-c command --command = command psqlが指定されたコマンド文字列commandを実行することを指定します。このオプションは、-fオプションを使用して繰り返し、任意の順序で組み合わせることができます。 -cまたは-fのいずれかが指定されている場合、psqlは標準入力からコマンドを読み取りません。代わりに、すべての-cおよび-fオプションを順番に処理した後に終了します。
commandは、サーバーが完全に解析できるコマンド文字列(つまり、psql固有の機能を含まない)または単一のバックスラッシュコマンドのいずれかでなければなりません。したがって、-cオプション内でSQLとpsqlメタコマンドを混在させることはできません。これを実現するには、次のように、繰り返し-cオプションを使用するか、文字列をpsqlにパイプします。
psql -c '\ x' -c 'SELECT * FROM foo;'または
echo '\ x\SELECT * FROM foo;' | psql(\はセパレーターのメタコマンドです。)
-cに渡される各SQLコマンド文字列は、単一のクエリとしてサーバーに送信されます。このため、文字列に複数のトランザクションに分割する明示的なBEGIN/COMMITコマンドが含まれていない限り、文字列に複数のSQLコマンドが含まれていても、サーバーはそれを単一のトランザクションとして実行します。また、psqlは文字列の最後のSQLコマンドの結果のみを出力します。これは、psqlが各SQLコマンドを個別に送信するため、同じ文字列がファイルから読み取られるか、psqlの標準入力に送られる場合の動作とは異なります。
この動作のため、単一の-c文字列に複数のコマンドを入れると、予期しない結果になることがよくあります。上に示したようにエコーを使用するか、シェルのヒアドキュメントを介して、繰り返し-cコマンドを使用するか、複数のコマンドをpsqlの標準入力にフィードすることをお勧めします。次に例を示します。
psql << EOF\x SELECT * FROM foo; EOF
そのため、スクリプトに統合するのに適しています。ps -ef
または同様のコマンドを使用して、パスワードが安全に保管され、表示されないようにしてください。
なぜCOPYは成功を報告するが何も書かない理由は何か?
最初に明白なものを除外する必要があります。サーバーはクライアントとは異なるマシンで実行できるため、それぞれの/tmp
は異なるものになります。 psql
の呼び出しには-h
オプションがないため、それがローカル接続であると仮定しましょう。
次の原因は、書き込みが失敗しないため、チェックインしているディレクトリとは異なるディレクトリに書き込むことです。
たとえば、systemd
は、特定のサービスにプライベート/tmp
および/var/tmp
ディレクトリを割り当てる場合があります。 systemdのドキュメントにPrivateTmpが表示され、OSの起動スクリプトがそれを使用しているかどうか、または同様のものを確認できます。
私はまた、DBA.seでこの関連するPostgreSQLの質問を見つけています。これは、書き込みではなく読み取りに関するものですが、同じ根本原因 PostgreSQL COPYで/ tmpから読み取ることはできませんが、別のディレクトリから同じファイルを読み取ることができますまったく同じ権限を持つ
簡単な解決策は、これらのエクスポートファイルに/tmp
を使用しないことです。特定のディレクトリを/var
の下のどこかに作成し、postgres
がそこに書き込み、ユーザーがそこから読み取れるようにする権限を付与します。