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

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

新規登録して質問してみよう
ただいま回答率
85.37%
SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

Q&A

解決済

2回答

6141閲覧

月別アーカイブを特定のカテゴリーのみにしたい

raidomaru

総合スコア106

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

0グッド

0クリップ

投稿2016/11/18 06:22

編集2016/11/22 12:08

###前提・実現したいこと
WordPressの中でアーカイブを作っています。
アコーディオン形式で年をクリックするとスライドダウンして、その年の投稿のある月と件数が表示される仕様です。
また、その月をクリックするとアーカイブへのリンクとなってます。

元々投稿のカテゴリーが一つでしたので
archive.php、category-a.php、single-a.phpに下記コードを記載していました。

###該当のソースコード

php

1 <div id="archives_year"> 2 <ul class="menu_list"> 3 <li> 4 <?php 5$year_prev = null; 6$months = $wpdb->get_results("SELECT DISTINCT MONTH( post_date ) AS month , 7 YEAR( post_date ) AS year, 8 COUNT( id ) as post_count FROM $wpdb->posts 9 WHERE post_status = 'publish' and post_date <= now( ) 10 and post_type = 'post' 11 GROUP BY month , year 12 ORDER BY post_date DESC"); 13foreach($months as $month) : 14$year_current = $month->year; 15if ($year_current != $year_prev){ 16if ($year_prev != null){?> 17 </ul> 18 <?php } ?> 19<div class="main_menu"><span><?php echo $month->year; ?></span></div> 20<ul class="sub_menu"> 21 <?php } ?> 22 <li> 23 <a href="<?php bloginfo('url') ?>/date/<?php echo $month->year; ?>/<?php echo date("m", mktime(0, 0, 0, $month->month, 1, $month->year)) ?>"> 24 <?php echo date("n", mktime(0, 0, 0, $month->month, 1, $month->year)) ?>25 (<?php echo $month->post_count; ?>) 26 </a> 27 </li> 28 <?php $year_prev = $year_current; 29 endforeach; ?> 30</ul> 31 32 </li> 33 </ul> 34 </div>

###発生している問題・エラーメッセージ

①追加で別のカテゴリーbを作ることになりました。
現在の記述ではカテゴリーaとb両方のアーカイブになっていますが、これを元のaのみにしたいです。
上記ソースのpost_typeの後に次のように書きましたがうまくいきませんでした。BDのテーブルが違うのかと考えてます。

php

1and post_type = 'post' and slug = 'a'

②それとは別にイベントというカスタム投稿を作りそちらのアーカイブも作成することになりました。
event organizerというプラグインを使用しています。
https://ja.wordpress.org/plugins/event-organiser/
内容は絞れたのですが、投稿日ではなくイベント日時でのアーカイブにしたいです。
こちらはpost_typeを次のように変更しました。

php

1and post_type = 'event'

SQLはそこまで知識がなくこちらのソースも数ヶ月前に調べながらどうにか作りました。
解決方法や別の作り方がありましたら、ご教授のほどよろしくお願いします。

###試したこと
下記ソースにしたところカテゴリーの絞りこみはできたのですが、記事数のカウントが増えてしまいました。
現在1記事のみしか公開していないのですが、4になってしまいます。

php

1 2$year_prev = null; 3$months = $wpdb->get_results("SELECT DISTINCT MONTH( post_date ) AS month , 4 YEAR( post_date ) AS year, 5 COUNT( id ) as post_count 6 FROM $wpdb->posts 7 LEFT JOIN $wpdb->postmeta 8 ON $wpdb->posts.ID = $wpdb->postmeta.post_id 9 LEFT JOIN $wpdb->term_relationships 10 ON $wpdb->posts.ID = $wpdb->term_relationships.object_id 11 LEFT JOIN $wpdb->term_taxonomy 12 ON $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id 13 LEFT JOIN $wpdb->terms 14 ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->terms.term_id 15 WHERE post_status = 'publish' and post_date <= now( ) 16 and post_type = 'post' and slug = 'column' 17 GROUP BY month , year 18 ORDER BY post_date DESC"); 19

###問題②解決方法
下記のようにソースを変更して解決しました。

php

1$year_prev = null; 2$months = $wpdb->get_results("SELECT MONTH( StartDate ) AS month , 3 YEAR( StartDate ) AS year, 4 COUNT( DISTINCT id ) as post_count FROM $wpdb->posts 5 LEFT JOIN $wpdb->eo_events 6 ON $wpdb->posts.ID = $wpdb->eo_events.post_id 7 WHERE post_status = 'publish' and post_date <= now( ) 8 and post_type = 'event' 9 GROUP BY month , year 10 ORDER BY StartDate DESC");

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kei344

2016/11/22 11:20

まだ質問が「受付中」になっていますが、いったん「解決済」にされてはいかがでしょうか。また、解決されていないなら状況をお教えください。
raidomaru

2016/11/22 11:29

発生している問題①は解決しましたが、②についてはこれから取り組みます。
kei344

2016/11/22 11:43

それは失礼しました、がんばってください。
guest

回答2

0

「試したこと」にご提示の SQL文の SELECT句を、以下のように変更してみてください。

Before

sql

1SELECT DISTINCT ... , COUNT( id ) as post_count
After

sql

1SELECT ... , COUNT( DISTINCT id ) as post_count

COUNT( id )では、テーブルを JOIN する過程で 1対n (n > 1) 関係のレコードが存在した場合、
重複を除外せずに id が NULL でないレコードの数を数え上げてしまいます。
https://dev.mysql.com/doc/refman/5.6/ja/group-by-functions.html#function_count

SELECT ステートメントで取得された行に含まれる expr の非 NULL 値の数を返します。

一方、COUNT( DISTINCT id )とすると、重複を除いた上で id が NULL でないレコードの数を取得できます。
https://dev.mysql.com/doc/refman/5.6/ja/group-by-functions.html#function_count-distinct

MySQL では、式のリストを指定することで、NULL が含まれない個別の式の組み合わせ数を取得できます。


また、yambejp様が回答で指摘されている通り、SELECT句自体の DISTINCT は不要です。

SELECT句内で集約関数を使用していないカラムと GROUP BY句に指定しているカラム(つまり、monthyear)が一致しているため、取得するデータ自体に重複はあり得ないからです。

投稿2016/11/22 09:49

編集2016/11/22 10:01
KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raidomaru

2016/11/22 10:40

こちらでもできました!ありがとうございます。
guest

0

ベストアンサー

group by してるから常にレコードはユニークなのでDISTINCTはいらないような気がします

ちなみに「 and slug = 'a'」にあたってslugカラムはどういうデータを保持していますか
aかbか''のどれかでしょうか?aとbの両方にカテゴライズされることはないのですか?

いずれにしろ、テーブルとかんたんなサンプルを表記し、
期待する結果を提示していただいたほうが適切な回答がつきやすいと思います

sample

SQL

1create table wp_posts(ID bigint(20) unsigned not null primary key auto_increment,post_date datetime); 2insert into wp_posts values(1,'2016-01-01 00:00:00'),(2,'2016-01-01 01:00:00'),(3,'2016-01-02 00:00:00'),(4,'2016-02-01 00:00:00'),(5,'2016-02-01 01:00:00'),(6,'2016-03-01 00:00:00'),(7,'2017-01-01 00:00:00'); 3

だったとして、抽出するSQLは

SQL

1select year(post_date) as year 2,month(post_date) as month 3,count(*) as count 4from wp_posts 5group by year,month 6order by year desc,month desc;

すると結果は

year month count 2017 1 1 2016 3 1 2016 2 2 2016 1 3

なり、PHPでいうとこんな感じ

/*抽出部分は省略*/ $months=[ (object) ["year"=>2017,"month"=>1,"count"=>1], (object) ["year"=>2016,"month"=>3,"count"=>1], (object) ["year"=>2016,"month"=>2,"count"=>2], (object) ["year"=>2016,"month"=>1,"count"=>3], ]; $html=""; $pre_year=0; foreach($months as $key=>$month){ $year=$month->year; if($pre_year!==$year){ if($key>0){ $html.="</ul>\n"; $html.="</div>\n"; } $html.="<div>\n"; $html.=sprintf("<h4>%s年</h4>\n",$year); $html.="<ul>\n"; } $html.=sprintf("<a href='#'>%s月(%s)</a></li>\n",$month->month,$month->count); $pre_year=$year; } if(count($months)>0){ $html.="</ul>\n"; $html.="</div>\n"; } print "<pre>\n"; print htmlspecialchars($html); print "</pre>\n";

投稿2016/11/18 06:55

編集2016/11/22 08:22
yambejp

総合スコア116468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raidomaru

2016/11/21 14:17

http://www.webopixel.net/wordpress/945.html 上記を参考に作成しました。 post_date.post_status,post_typeはwp_postsというテーブルにカラムがあり slugはwp_termsというテーブルにカラムが存在してます。 現在18個のslugがありますが、aとbの両方にカテゴライズされるものはありません。 残りの16個は全てbの子カテゴリです。
yambejp

2016/11/21 14:25

見た感じ肝心のDBのテーブル構造やデータサンプルが無いので 結果を導くSQL文が書きようがありませんね
yambejp

2016/11/22 08:18

なるほどなんとなくわかってきました wp_termsのslugをwp_term_taxonomy、wp_term_relationshipsを経由して リレーションすればよいのではないですか?
raidomaru

2016/11/22 08:38

色々と調べながらSQL書いてみてカテゴリーは絞れましたが、記事のカウント数がおかしくなってしまいました。どこかで重複カウントしているのでしょうか。
yambejp

2016/11/22 08:51

inner joinで繋いでいく限り n対nでリレーションしなければ合うと思うんですが 多段でつなぐとそれなりに調整が必要なのかもしれません
退会済みユーザー

退会済みユーザー

2016/11/22 10:00

横入りで失礼しますが、一言だけ。 「試したこと」で記載されたSQLを見る感じ、$wpdb->postmetaのLEFT JOINがいらないんじゃないかと思います。
raidomaru

2016/11/22 10:40

LEFT JOIN $wpdb->postmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id まで削除したらうまくできました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問