0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【非PDO】PHP+PostgreSQLで日付型をINSERT→UPDATEする(prepared&bind)

Last updated at Posted at 2021-07-13

やたら苦戦してしまったのでメモに残します。

やりたいこと

  • 変数$calc_dateには""もしくは日付YYYY-MM-DDを表す文字列が入る。
  • この変数をdate型のカラムにアップサートしたい。(INSERTして重複する場合はUPDATEしたい。)
  • SQL文はプリペアードしたものにバインドしたい。
  • pg_prepare, pg_executeを使用する。(PDOを使用しない)
  • 環境:PHP7、PostgreSQL12

実装

// DB接続処理
$link = pg_connect("host=host_name port=XXXX dbname=db_name user=user_name password=XXXX");

// 日付もしくは""の配列
$date_list = ["", "2021-07-13", "", "2020-09-01"];

// テーブルINSERT(重複したらUPDATE)のSQL
$sql = 'INSERT INTO table_name (id, sample_date)
            VALUES ($1, $2)
        ON CONFLICT (id)
        DO UPDATE SET  sample_date = $3
        ';

// プリペアードステートメント作成(preparedする)
$res = pg_prepare(
            $link,
            'pr_table_name01', // ←これはプリペアードステートメントの名前
            $sql
        );

$cnt = 0;
foreach($date_list as $row){
    $cnt = $cnt + 1;
    // 日付もしくは""が入る
    $calc_date = $row;

    // ""だったらnull、それ以外は''(シングルクオート)で囲う
    $calc_date = $calc_date == "" ? null : '\''.$calc_date.'\'';

    // プリペアードステートメント実行(bindする)
    $res = pg_execute(
               $link,
               'pr_table_name01',
               [$cnt, $calc_date, $calc_date]
           );
}
//DB後処理
$close_flag = pg_close($link);

キーポイント

  • PostgreSQLのdate型には null か日付しか入らない。""(空文字)は不可。
  • ON CONFLICT文はPostgreSQL独自の構文。MySQLではON DUPLICATE KEYを使う。
  • 日付形式の文字列をバインドする時は''で囲う。(nullは囲んじゃダメ!)

参考:ループ内でプリペアードステートメントを作成

foreach内でpreparedしたい場合は、最初の1回のみ行うようにする。

// DB接続処理
$link = pg_connect("host=host_name port=XXXX dbname=db_name user=user_name password=XXXX");

// 日付もしくは""の配列
$date_list = ["", "2021-07-13", "", "2020-09-01"];
$cnt = 0;
foreach($date_list as $row){
    $cnt = $cnt + 1;
    // 日付もしくは""が入る
    $calc_date = $row;

    // ""だったらnull、それ以外は''(シングルクオート)で囲う
    $calc_date = $calc_date == "" ? null : '\''.$calc_date.'\'';

    // テーブルINSERT(重複したらUPDATE)のSQL
    $sql = 'INSERT INTO table_name (id, sample_date)
                VALUES ($1, $2)
            ON CONFLICT (id)
            DO UPDATE SET  sample_date = $3
           ';

    // 1回目のみプリペアードステートメント作成(preparedする)
    if($cnt == 1) {
       $res = pg_prepare(
                  $link,
                  'pr_table_name01', // ←これはプリペアードステートメントの名前
                  $sql
              );
    }
    // プリペアードステートメント実行(bindする)
    $res = pg_execute(
               $link,
               'pr_table_name01',
               [$cnt, $calc_date, $calc_date]
           );
}
//DB後処理
$close_flag = pg_close($link);

今どきはPDOが主流なので(プロジェクトの方針で禁止されない限り)PDO形式が良いと思います。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?