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

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

ただいまの
回答率

91.26%

  • PHP

    15661questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • MySQL

    4563questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • PDO

    284questions

    PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。

【MYSQL】【PHP】データベース操作で効率的なループ処理を行う方法【初心者】

解決済

回答 1

投稿 編集

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

shimane

score 73

現在、プログラムの勉強をしている者です。
勉強目的でサイトを作成して「アクセス解析」も簡単なものを作成する事が出来ました。

アクセス解析の中のIN数とOUT数を集計する部分で壁にあたっています。

当サイトへのIN数と
当サイトからの登録したブログへの送ったOUT数を集計する際に
効率的なコードの書き方に悩んでいます。

現在、勉強中という事もあり
とても単純な方法でコードを書いたのですが
単純な方法だった為、条件分岐を登録しているブログの数だけ書かないといけなくなり
効率の面でも処理の面でも大変な事になっています。

これを効率的に書く方法について教えて頂けると嬉しいです。

テーブル説明:
テーブル名:blog(記事URL,記事タイトル,ブログ名等が入っています。)

テーブル名:incount(参照元URL,IP等が入っています。)

テーブル名:outcount(飛んだ先のURL等が入っています。)

テーブル名:site(登録ブログ名,登録ブログのURL,IN数,OUT数等が入っています。)

IN数とOUT数の集計
登録ブログAのURLが「http://test.com/」だった場合(ドメインは「test.com」が登録されています。)

//アクセス集計のIN数が入っているテーブル:「incount」のURLが入っているカラム:「referer 」にて
//test.comに部分一致している数を集計します。
$stmt = $db->query("select count(*) as cnt from incount where referer LIKE '%test.com%'");
$incount = $stmt->fetchColumn();

//アクセス集計のOUT数が入っているテーブル:「outcount」のURLが入っているカラム:「out_url 」にて
//test.comに部分一致している数を集計します。
$stmt = $db->query("select count(*) as cnt from outcount where out_url LIKE '%test.com%'");
$outcount = $stmt->fetchColumn();

//テーブル:siteにてIN数とOUT数を書き込む為に
//該当する登録ブログを「test.com」にて検索しています。
$sitedomain = "test.com";
$stmt = $db->prepare("select * from site where sitedomain = :seachword limit 1");
$stmt->bindParam(':seachword', $sitedomain);
$stmt->execute();
$inoutseach = $stmt->fetchAll(\PDO::FETCH_OBJ);

//foreachで1回だけループ回しています。
foreach($inoutseach as $inout) {

//ここで集計したIN数とOUT数をテーブル:「site」の該当するカラムにアップデート更新します。
//$sitedomainにて検索しています。($sitedomainには「登録ブログのドメイン」が入っています。)
$stmt = $db->prepare("update site set incount = :incount,outcount = :outcount
where sitedomain = :domain");
$stmt->execute([
  ':incount' => $incount,
  ':outcount' => $outcount,
  ':domain' => $sitedomain
]);
}

このコードでアクセス解析で取得したIN数とOUT数を集計して
siteテーブルに集計結果を書き込む事が出来たのですが、
これですと

//ここの部分にて登録ブログのドメインを手動でいれなくてはいけない為、
//登録ブログの数だけ、複数のコードが必要になってしまいます。
$sitedomain = "test.com";

登録しているブログの数だけコードを複数書いていかないといけなく、
(登録ブログが10個なら10個コードを書かなくてはいけません。)
もっと効率的な書き方があるのでは?と考え、
色々と調べたり、試してみたのですが上手くいきませんでした。

テーブル名:site
このテーブルにあります
カラム名:
name,(登録ブログの名前が入っています。)
url,(登録ブログのURLが入っています。)
url_domain,(登録ブログのURLのドメインが入っています。)
rss_url,(登録ブログのRSSのURLが入っています。)

ここの「ドメイン」が入っている「url_domain」を利用する事が出来たら
手動で登録ブログのドメインを設定する必要が無く
登録ブログが設定されている回数分(5個登録していたら5回ループを回す)だけループ処理で 
siteテーブルの
1週目:url_domain(ドメイン)の1番目を$sitedomainに指定
2週目:url_domain(ドメイン)の2番目を$sitedomainに指定
3週目:url_domain(ドメイン)の3番目を$sitedomainに指定
といった風にできれば・・・と理想を抱いて試行錯誤を繰り返しているのですが
実力が足りず、上手くいきませんでした。
私に出来たのは上の方にある、手動で設定していく簡単なコードで精一杯でした。

解決方法をご存知の方や
何かお気付きになられた点がありましたら
お力をお貸し頂けると嬉しいです。
どうかよろしくお願いします。


テーブルの構造です。
遅れてしまって申し訳ありません。

テーブル名:incount

mysql> SHOW CREATE TABLE incount;
+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                           |
+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| incount | CREATE TABLE `incount` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `datetime` datetime NOT NULL,
  `ip` varchar(50) NOT NULL,
  `url_file` varchar(255) NOT NULL,
  `referer` varchar(255) NOT NULL,
  `user_agent` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=649 DEFAULT CHARSET=utf8 |
+---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

テーブル名:outcount

mysql> SHOW CREATE TABLE outcount;
+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table    | Create Table                                                                                                                                                                                                                                                                                                        |
+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| outcount | CREATE TABLE `outcount` (
  `id` int(50) NOT NULL AUTO_INCREMENT,
  `datetime` datetime NOT NULL,
  `ip` varchar(100) NOT NULL,
  `out_url` varchar(255) NOT NULL,
  `user_agent` varchar(255) NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=85 DEFAULT CHARSET=utf8 |
+----------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

テーブル名:site

mysql> SHOW CREATE TABLE site;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| site  | CREATE TABLE `site` (
  `id` int(22) NOT NULL AUTO_INCREMENT,
  `name` varchar(120) NOT NULL,
  `url` varchar(200) NOT NULL,
  `siterss` varchar(200) NOT NULL,
  `sitedomain` varchar(100) NOT NULL,
  `incount` int(20) NOT NULL DEFAULT '0',
  `outcount` int(20) NOT NULL DEFAULT '0',
  `henkan` float NOT NULL DEFAULT '0',
  `rsscount` int(10) NOT NULL DEFAULT '0',
  `lastdate` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • shimane

    2017/12/16 13:42

    何度も申し訳ありません。今、記載致しました。 こういう事も経験がありませんでしたのでとても勉強になりました。今度からは教えて頂いた通りにしていきます。感謝です!

    キャンセル

  • Kosuke_Shibuya

    2017/12/16 13:43

    こうしてくれると、回答者は楽なんです。CREATE 〜 charset=?? まで書かれていると、手元で実験しやすいので。

    キャンセル

  • shimane

    2017/12/16 13:46

    書籍やドットインストールさんやネットの情報で勉強していて、学校や職場でプログラムの事を教えて頂くといった経験が無かったので、とても良い事を教えて頂けました。大感謝です!

    キャンセル

回答 1

checkベストアンサー

+2

UPDATE `site` SET 
  `incount` = (select count(*) as cnt from incount where referer LIKE CONCAT('%', `site`.`sitedomain`, '%'))
  , `outcount` = (select count(*) as cnt from incount where referer LIKE CONCAT('%', `site`.`sitedomain`, '%'))

多分これで、行けると思う。
検証はしていません。

検証が必要な場合、はテーブル定義を CREATE TABLE 〜 で提示してください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/16 13:55

    回答有難うございます!

    私の説明が上手くいかず、申し訳ありません。
    今回、質問させて頂いたのは

    今の私の実力だと
    変数:$sitedomain(登録ブログのドメインを入れます。)に対して
    手動でドメインを入れていかなければならず、
    その為に登録ブログの数だけ、コードを複数書かないといけません。
    (現在は登録ブログが10個なら10個コードを書いています。)

    これを効率よくするために

    テーブル:siteに登録されているブログの数だけ「ループを回して」
    $sitedomainの中に「カラム:sitedomain」に登録されているドメインを自動的に入れていければ
    手動で設定せずに
    IN数とOUT数の集計結果を該当する登録ブログに書き込む事が出来るのではないかな?
    と思っているのですが
    実力が足りなくて、上手く出来ていません。
    この「登録ブログの数だけループを回す」+「変数にドメイン名を自動で入れていく」が
    試行錯誤しても上手くいきませんでした。
    何かお気付きの点がありましたらお力をお貸し頂けると嬉しいです。

    キャンセル

  • 2017/12/16 13:58

    このクエリを実行すると、ループを使う必要がありません。
    全ての登録されているドメインに対して、更新が可能です。

    キャンセル

  • 2017/12/16 14:13

    素晴らしいです!

    ループ処理といえば
    foreach()という意識がありました。
    まさかあんなにも多かったコードがこんなにも短縮出来るなんて!!

    これが本物のプログラム技術者の人なんですね。
    本当にびっくりしました。
    私ももっともっと勉強していこうと思います。
    悩んで悩んでそれでも解決出来なかった事でしたので本当に助かりました!

    大感謝です!

    キャンセル

  • 2017/12/16 15:18 編集

    そもそもですが、UPDATEが一発でできるということはSELECTも一発でできるということはお気付きですか?
    つまり、設計上 site テーブルに それぞれのカウント数を保存するカラムは不要です。パフォーマンス対策である場合を除いて。

    キャンセル

  • 2017/12/16 15:42

    !!
    そうか、そうですよね。
    たしかにそうです!

    今はまだまだ基礎の基礎を勉強している段階なので
    1歩1歩進んで行くのを意識しているので、
    念のために集計・結果を書き込み・変更といった作業を通してプログラムの勉強をしていく予定ですが
    教えて頂いた考え方を頭の中にいれて勉強を進めていこうと思います。

    今日は本当に色々な事が勉強出来てとても充実した1日になりました。
    有難うございます。感謝です!

    キャンセル

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

ただいまの回答率

91.26%

関連した質問

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

  • PHP

    15661questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • MySQL

    4563questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • PDO

    284questions

    PDO(PHP Data Objects)はPHPのデータベース抽象化レイヤーです。