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

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

ただいまの
回答率

87.59%

【MYSQL】【PHP】更新時間を基準にしての並び替えを行う方法【初心者】

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 1,083

score 90

現在、PHPとMYSQLの勉強をしながらサイトを作成しています。

記事をデータベースに保存して
mysqlを使ってサイトに表示するという事を行っています。

【事前情報】

記事タイトル
記事URL
カテゴリ名(100種類ぐらいあります。)
更新日時
PV数(ページビュー数)


【やりたい事】

トップページにて「記事を表示」する際に「更新日時」と「PV数」を基準にして
並び替えをしたいです。

単純な更新日時の順番だと「PV数」が少ない人気の無い記事が一番最初に表示される事もあるので
20分以内に更新された記事の中から「PV数が多い順番」に並び替えをしたいと考えております。
(すべての記事を表示しつつ、20分以内に更新された記事の中からPV数の多い順番に並び替え)


【例】
すべての記事を表示させつつ
更新日時が20分以内の記事の中からPV数が多い順番に並び替えを行いたいです。

記事A
カテゴリ:日本
PV:100
更新日時:20分以内

記事B
カテゴリ:アメリカ
PV:90
更新日時:20分以内

記事C
カテゴリ:中国
PV:90
更新日時:20分以内

↑は更新日時が20分以内の記事で、PV数の多い順番に並び替えが成功している状態です。

ここから下にはさらに20分間間隔で
その20分間間隔の記事の中からPV数の多い順番に並び替えが成功している状態です。

記事D
カテゴリ:カナダ
PV:500
更新日時:40分以内

記事E
カテゴリ:アメリカ
PV:900
更新日時:80分以内

記事F
カテゴリ:中国
PV:9000
更新日時:100分以内


【試してみた事】

ネットで色々検索してみた所
希望している完成に近付ける事は出来ました。

更新日時:created
PV数:pv
ページナビゲーション機能に利用:. $offset . "," . $pagelimit

$stmt = $db->query("select * from bbs 
  order by date_format( created, '%Y-%m-%d %H:%i' ) desc, pv desc limit " . $offset . "," . $pagelimit);
  $mysqlall = $stmt->fetchAll(\PDO::FETCH_OBJ);

これで更新された記事を1分単位でのPV数が多い順番に並び替えをする事が出来ました。
1分単位だと該当する記事の数が少なすぎて
不人気な記事でも先頭に表示されてしまいます。

ですので、これが1分単位ではなくて「20分間」単位になるのが理想とする形です。

色々試してみた所「1時間単位」には設定する事が出来ました。

$stmt = $db->query("select * from bbs 
  order by date_format( created, '%Y-%m-%d %H' ) desc, pv desc limit " . $offset . "," . $pagelimit);
  $mysqlall = $stmt->fetchAll(\PDO::FETCH_OBJ);


該当する記事が増えたのですが
1時間だと時間があまりにも長すぎるので「20分間」を理想としているのですが上手くいきません。

またこちらの方法でも試してみました。

$stmt = $db->query("select * from bbs where created > CURRENT_TIMESTAMP + INTERVAL - 20 MINUTE order by pv desc limit " . $offset . "," . $pagelimit);
  $mysqlall = $stmt->fetchAll(\PDO::FETCH_OBJ);

上のコードですと「20分間間隔」での「pV数」の並び替えを行う事が出来ましたが
「20分以内の記事だけ」しか表示されず、
すべての記事を表示しつつ「20分間間隔」での「pV数」での並び替えを行う事が出来ませんでした。
(20分以内の記事が10件だけなら、その10件だけが表示されて終わってしまいます。)
(総記事数が1000件でも「10件」だけが表示される事になるので、困っています。)

私なりにネットで調べたり書籍で調べても上手くいきません。

すべての記事を表示しつつ「20分間間隔」での「pV数」での並び替えを行う方法をご存知の方や
解決する為の方法に何か心当たりのある方は教えて頂けないでしょうか?
お力をお貸し頂けると嬉しいです。

どうかよろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+2

floor(TIMESTAMPDIFF(MINUTE,created ,now())/20)


とすれば、20分単位の経過数値がわかります

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/20 10:42

    yambejpさん回答有難うございます。

    教えて頂いたコードを試してみました。

    $stmt = $db->query("select * from bbs
    order by floor(TIMESTAMPDIFF(MINUTE,created ,now())/20)ASC, pv desc limit " . $offset . "," . $pagelimit);
    $mysqlall = $stmt->fetchAll(\PDO::FETCH_OBJ);

    実行結果:
    まさに理想とする20分間以内の記事のPV数の大きい順番の並び替えを行う事が出来ました!
    本当に素晴らしいです。大感謝です!+評価とベストアンサーをさせて頂きます。
    助けて頂きまして本当に有難うございます。

    キャンセル

+2

成功している「1時間間隔+PV数でソート」から、どうやったら「20分間隔」にできるかを考えましょう。

UNIX秒という概念はご存知ですか?1970-01-01 00:00:00から何秒経ったかという時間の概念です。例えば2017-10-20 12:00:00(日本標準時刻)1508468400という数字になります。では秒が分かればこれを20分ごとに分割してやればよいのです。20分は60秒×20分なので2400秒ですね。ではUNIX秒を2400で割って切り捨ててしまえば20分ごとの区切りになります。

TIMESTAMP型からUNIX秒を求めるにはUNIX_TIMESTAMP関数を、切り捨てはFLOOR関数を使います。

$stmt = $db->query("select * from bbs 
  order by FLOOR(UNIX_TIMESTAMP(created) / 2400) desc, pv desc limit " . $offset . "," . $pagelimit);

ということで、これで希望の結果になるでしょうか?検証してみてください。

 蛇足

SQLに変数を渡す際にはプリペアドステートメントを使いましょう。SQLに文字列として結合して使うやり方はセキュリティ的に超危ない行為です。
http://php.net/manual/ja/pdo.prepared-statements.php

$stmt = $db->prepare("select * from bbs 
  order by FLOOR(UNIX_TIMESTAMP(created) / 2400) desc, pv desc limit :offset, :pagelimit");
$stmt->bindParam(':offset', $offset, PDO::PARAM_INT);
$stmt->bindParam(':pagelimit', $pagelimit, PDO::PARAM_INT);
$stmt->execute();
$mysqlall = $stmt->fetchAll(\PDO::FETCH_OBJ);

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/10/20 12:06

    あー、申し訳ない。$offsetや$pagelimitが文字列として扱われてしまっていますね。数値扱いしてもらえるように回答を修正しておきます。

    キャンセル

  • 2017/10/20 12:09

    有難うございます!今度からこのエラーが出た時には
    今回教えて頂いたような対応をしたいと思います!

    キャンセル

  • 2017/10/20 12:10

    おおおお、有難うございます!, PDO::PARAM_INTを追加しましたら
    正常にすべてばっちりに表示されました。本当に助かりました!

    今後もいっぱいいっぱい勉強を進めていこうと思います!大感謝です!

    キャンセル

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

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

関連した質問

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