質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.98%

mysqlからpostgresqlに変更したい

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 315

ariiiiiga

score 40

前提・実現したいこと

mysqlからpostgresqlに変更した際に出力が変わってしまいました。
・予約件数の表示がshop_idと結びついていなく、reserveレコードに入っている全件をカウントしてしまう。
・予約情報が表示されない($arr_reserveが空になっている)

reserveレコードに入っている予約ID(reserve_shop_id)とログイン時にsessionに入ったログインID(shop_id)で一致した情報を取り出して、ページング機能を使いreserveテーブルにデータが入ったのが遅い順(reserve_time)で表示させたいです。
MYSQLではSQL_CALC_FOUND_ROWSを使っていましたがPostgresqlでは使えないようなので同じように動かしたいです。
調べましたが解決策がわかりませんでした。

どう直すのか教えて頂けると助かります。

該当のソースコード

変更前のMYSQL
//予約情報の取り出し
SELECT SQL_CALC_FOUND_ROWS * FROM reserve WHERE reserve_shop_id=:shop_id  ORDER BY reserve_time DESC limit :limit offset :offset;

// 予約Total件数
SELECT FOUND_ROWS() as total;
変更後のPostgresql
//予約情報の取り出し
SELECT * FROM reserve WHERE reserve_shop_id=:shop_id ORDER BY reserve_time DESC limit :limit offset :offset;

// 予約Total件数
SELECT COUNT(*) as total;
全体
<?php
  error_reporting(E_ALL);
  ini_set("display_errors",1);
  session_start();
  try {
    //接続済み
    $pdo = new PDO(DSN,DB_USER,DB_PASS);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
    $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);


    // ①ユーザーIDからユーザー名を取り出す
    $query = "SELECT * FROM shop WHERE shop_id=:shop_id";
    $shop_stmt = $pdo->prepare($query);
    $shop_stmt->bindValue(':shop_id', $_SESSION['user'], PDO::PARAM_INT);
    $shop_stmt->execute();

    // ショップ情報の取り出し
    $row = $shop_stmt->fetch(PDO::FETCH_ASSOC);
    $shop_id = $row['shop_id'];
    $shop_name = $row['shop_name'];
    $yesno = $row['yesno'];
    $shop_comment = $row['shop_comment'];
    $shop_email = $row['shop_email'];
  
  // 予約情報の取り出し
    $sql = $pdo->prepare('select * from reserve where reserve_shop_id=:shop_id order by reserve_time desc limit :limit offset :offset');
    $sql->bindValue(':shop_id', $_SESSION["user"], PDO::PARAM_INT);
    $sql->bindValue(":offset", $offset, PDO::PARAM_INT);
    $sql->bindValue(":limit", PAGE_LIMIT, PDO::PARAM_INT);
    $sql->execute();

    $arr_reserve = [];
    while ($result = $sql->fetchAll(PDO::FETCH_ASSOC)){
      $arr_reserve[] = [
        'reserve_shop_id' => $result['reserve_shop_id'],
        'reserve_comment' => $result['reserve_comment'],
        'reserve_time' => $result['reserve_time'],
      ];
    }

    // 予約Total件数
    $totalRow = $pdo->prepare("SELECT COUNT(*) as total from reserve");
    $all = $totalRow->fetch(PDO::FETCH_ASSOC);

} catch (PDOException $e) {
   var_dump($e);
   die();
}
?>
<!DOCTYPE HTML>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>トップ</title>
  </head>

  <body>
     <main>

          <p class="alert alert-success" style="text-align:center;">予約数<?=htmlspecialchars($all['total']),ENT_QUOTES,'utf-8'); ?></p>
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>コメント</th>
                  <th>予約時間</th>
                 </tr>
              </thead>
              <tbody>
                <?php foreach($arr_reserve as $key => $value): ?>
                  <tr>
                    <td><?= htmlspecialchars($value['reserve_comment'], ENT_QUOTES, 'UTF-8'); ?></td>
                   <td><?= htmlspecialchars($value['reserve_time'], ENT_QUOTES, 'UTF-8'); ?></td>
                  <tr>
                <?php endforeach; ?>
              </tbody>
            </table>



      </main>
    </div>
  </body>
</html>

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m6u

    2019/07/02 13:56

    質問者さんの思考の流れが全く読めない修正内容なので、丁寧に細かく一つ一つ段取りを説明していただきたい。MySQLからPostgreSQLに直すことはよくあるけど、ただそれに便乗していろんな直しを盛り込んではいないだろうかと察しているのだが。その盛り込んだ話はそもそも何をしようとしてそう直そうとしたのかも、丁寧に。

    キャンセル

  • m.ts10806

    2019/07/10 09:28

    既にほぼ解決可能な回答がついているのに「まだ回答を求めています」とはどういうことでしょうか。

    キャンセル

  • m.ts10806

    2019/07/23 17:51

    (2回目)
    既にほぼ解決可能な回答がついているのに「まだ回答を求めています」とはどういうことでしょうか。

    キャンセル

回答 2

0

憶測で、

SELECT reserve_time, COUNT(*) FROM reserve WHERE reserve_shop_id=:shop_id GROUP BY reserve_time ORDER BY reserve_time DESC;


なら指定されたreserve_shop_idのreserve_time毎の件数を表示しますが、

SELECT COUNT(*) FROM reserve WHERE reserve_shop_id=:shop_id ORDER BY reserve_time DESC;


は指定されたreserve_shop_idの1行しか結果が出ないのでORDER BYがあっても無駄だよ、って怒られいるのでは?

同じSQLでもデータベースやそのバージョンによって方言が大きいです。SQLの観点から Oracle Database, PostgreSQL, MySQL の特徴を整理しよう!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

ほぼ答えのコメントを書いたのですが、スルーされるので回答にします。
count関数は集約関数です。
データを集約した上で結果を出します。

しかも別のカラムをSELECTに使用しない限りは一件しか結果が出ません。
一件しか出ないことが決まっているのにorder byは無駄です。(しかもcountには*を指定しているので全カラム指定)

さらに。order byは並べ替えを行う機能です。並べ替えを行いたければそのカラムも何かしらの形で集約する必要があります。集約関数を使うか、group byでまとめるしかありません。

このSQLだけだされてもアプリケーションでどのように使用されるか分からないですが、「reserve_shop_idで絞りこんだ結果の全件数」を出したい、のであればorder by部分をなくして、
SELECT COUNT(*) FROM reserve WHERE reserve_shop_id=:shop_id
だけでいいです。

※どういう結果を出したくてどう調べたのかが提示されていないので出来る回答はここまでです。

追記。
DBの種類が変わるときのコツ。
以下のどれか(上から順に推奨度が低いもの)

  1. 方言や文法が全く変わることもあるので、今あるものをどうにかするのではなく、今あるものは一旦捨ててどう出したいデータかを考えて最初から組み直す
  2. 初めからそのDBにしか存在しないような機能は使わない
  3. フレームワークを導入する

まあ、フレームワーク導入が一番ですね。
それに今回くらいの内容だとMySQLにしかない機能を使わなくても実現可能なので(offset,limitの書き方くらい)
最低でも2番目で組んでおくべきです。
「どうしてもそのDBにしかない機能を使わなきゃいけない場面」ってそうそうなくて、汎用的に組むことは可能です。

追記されたので追記:

reserveレコードに入っている予約ID(reserve_shop_id)とログイン時にsessionに入ったログインID(shop_id)で一致した情報を取り出して、ページング機能を使いreserveテーブルにデータが入ったのが遅い順(reserve_time)で表示させたいです。  
MYSQLではSQL_CALC_FOUND_ROWSを使っていましたがPostgresqlでは使えないようなので同じように動かしたいです。  

count()のSQLとorder by ,offset limit を指定したSQL 
2回実行すれば良いです。これならDB変わっても影響は少ないでしょう。

が、

うっすら記憶があったので探したところ、ずいぶん前のご自身の質問OVER()とか使われてましたけど、あれは結局何だったのでしょうか。おそらくこのような記事を参考にして作ったのでしょうけど、ちゃんと組めば動きますよ(私も手元で確認しました)

SELECT
 *
 ,COUNT(*) OVER() AS found_rows
FROM
  TEST
WHERE
  delete_flg = '0' 
  LIMIT 5 OFFSET 0

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.98%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る