web-dev-qa-db-ja.com

psqlスクリプトでCOPYを使用してもファイルに書き込まれない

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ユーザーにスーパーユーザーを許可しようとしました。

2
haki

通常は\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サーバーコマンドです。
  • \COPYCOPYのように作成されたPostgreSQLクライアント(psql)コマンドです
4
Evan Carroll

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または同様のコマンドを使用して、パスワードが安全に保管され、表示されないようにしてください。

0
Vérace

なぜCOPYは成功を報告するが何も書かない理由は何か?

最初に明白なものを除外する必要があります。サーバーはクライアントとは異なるマシンで実行できるため、それぞれの/tmpは異なるものになります。 psqlの呼び出しには-hオプションがないため、それがローカル接続であると仮定しましょう。

次の原因は、書き込みが失敗しないため、チェックインしているディレクトリとは異なるディレクトリに書き込むことです。

たとえば、systemdは、特定のサービスにプライベート/tmpおよび/var/tmpディレクトリを割り当てる場合があります。 systemdのドキュメントにPrivateTmpが表示され、OSの起動スクリプトがそれを使用しているかどうか、または同様のものを確認できます。

私はまた、DBA.seでこの関連するPostgreSQLの質問を見つけています。これは、書き込みではなく読み取りに関するものですが、同じ根本原因 PostgreSQL COPYで/ tmpから読み取ることはできませんが、別のディレクトリから同じファイルを読み取ることができますまったく同じ権限を持つ

簡単な解決策は、これらのエクスポートファイルに/tmpを使用しないことです。特定のディレクトリを/varの下のどこかに作成し、postgresがそこに書き込み、ユーザーがそこから読み取れるようにする権限を付与します。

0
Daniel Vérité