sql >> データベース >  >> RDS >> PostgreSQL

エラー:PostgreSQL COPYを使用すると、最後に予期された列の後に余分なデータがあります

    空のテーブルは機能しません。入力データの構造に一致するテーブルが必要です。次のようなもの:

    CREATE TABLE raw_data (
      col1 int
    , col2 int
      ...
    );
    

    tabを宣言する必要はありません DELIMITERとして これがデフォルトなので:

    COPY raw_data FROM '/home/Projects/TestData/raw_data.txt';
    

    あなたが言う800列?その数の列は通常、設計に問題があることを示します。とにかく、 CREATE TABLEを半自動化する方法があります スクリプト。

    自動化

    単純化された生データを想定する

    1   2   3   4  -- first row contains "column names"
    1   1   0   1  -- tab separated
    1   0   0   1
    1   0   1   1
    

    別のDELIMITERを定義します (インポートデータではまったく発生しないもの)、単一の textを使用して一時ステージングテーブルにインポートします。 列:

    CREATE TEMP TABLE tmp_data (raw text);
    
    COPY tmp_data FROM '/home/Projects/TestData/raw_data.txt' WITH (DELIMITER '§');
    

    このクエリは、 CREATE TABLEを作成します スクリプト:

    SELECT 'CREATE TABLE tbl (col' || replace (raw, E'\t', ' bool, col') || ' bool)'
    FROM   (SELECT raw FROM tmp_data LIMIT 1) t;
    

    より一般的で安全なクエリ:

    SELECT 'CREATE TABLE tbl('
        ||  string_agg(quote_ident('col' || col), ' bool, ' ORDER  BY ord)
        || ' bool);'
    FROM  (SELECT raw FROM tmp_data LIMIT 1) t
         , unnest(string_to_array(t.raw, E'\t')) WITH ORDINALITY c(col, ord);
    

    返品:

    CREATE TABLE tbl (col1 bool, col2 bool, col3 bool, col4 bool);
    

    有効性を確認してから実行するか、結果が信頼できる場合は動的に実行します。

    DO
    $$BEGIN
    EXECUTE (
       SELECT 'CREATE TABLE tbl (col' || replace(raw, ' ', ' bool, col') || ' bool)'
       FROM  (SELECT raw FROM tmp_data LIMIT 1) t
       );
    END$$;
    

    次に、 INSERT このクエリのデータ:

    INSERT INTO tbl
    SELECT (('(' || replace(replace(replace(
                      raw
                    , '1',   't')
                    , '0',   'f')
                    , E'\t', ',')
                 || ')')::tbl).*
    FROM   (SELECT raw FROM tmp_data OFFSET 1) t;
    

    または、 translate()

    INSERT INTO tbl
    SELECT (('(' || translate(raw, E'10\t', 'tf,') || ')')::tbl).*
    FROM   (SELECT raw FROM tmp_data OFFSET 1) t;
    

    文字列は行リテラルに変換され、新しく作成されたテーブル行タイプにキャストされ、(row)。*で分解されます。 。

    すべて完了しました。

    これらすべてをplpgsql関数に入れることもできますが、SQLインジェクションから保護する必要があります。 (SOには関連するソリューションがいくつかあります。検索してみてください。

    db <> fiddle こちら
    Old SQL Fiddle



    1. mysqlプロファイラーデータの送信

    2. MySQL追跡システム

    3. mysqliに多くの値を挿入する最良の方法は?

    4. 非オブジェクトの関数bind_param()| PHP MySQL