jQuery でセレクターの指定2
前回jQueryでセレクター指定の記事を書いたのですが まだセレクターについて書くことがあったので記載していきます。
前回の記事はこちらになります。 nonaka-katuma-hal.hatenablog.com
初期状態はこのようになっているものとします。
HTML
<ul> <li>テキストテキスト</li> <li>テキストテキスト</li> <li>テキストテキスト</li> <li>テキストテキスト</li> </ul>
1.ユニバーサルセレクター
全ての要素を選択するもので*(アスタリスク)で記述します。
HTML
<ul> <li><a>テキスト</a>テキスト</li> <li><a>テキストテキスト</a></li> <li><a>テキストテキスト</a>テキスト</li> <li>テキストテキスト</li> </ul>
$(function() { $("li *").css("color","red"); });
li要素内に含まれる全ての要素、つまりaタグで囲まれたものが赤色になります。
2.グループセレクター
複数のセレクターを,(カンマ)区切りで並べて指定できるのがグループセレクターです。 それぞれのセレクターに対する命令をまとめて記述出来ます。
HTML
<ul> <li id="first">テキストテキスト</li> <li id="second">テキストテキスト</li> <li id="third">テキストテキスト</li> <li id="fourth">テキストテキスト</li> </ul>
$(function() { $("#second , #fourth").css("color","red"); });
id属性がsecondの2番目とfourthの4番目のli要素が赤色になります。
3.子セレクター
特定の要素の直下に配置された要素を選択できるのが「子セレクター」です。 子セレクターは親要素と子要素を「>」で結びます。
HTML
<ul> <li id="first"><a>テキスト</a>テキスト</li> <li id="first"><a>テキストテキスト</a></li> <li id="first"><div>テキスト<a>テキスト</a></div></li> <li id="second"><a>テキスト</a>テキスト</li> </ul>
$(function() { $("#first > a").css("color","red"); });
1行目2行目のidがfirstの直下のaタグに囲まれた文字だけ赤色になります。 3行目のaタグに囲まれた文字はdivの直下になっているので赤色になりません。
4.隣接セレクター
特定の要素の次に出現する要素を選択できるのが「隣接セレクター」です。 隣接セレクターは隣接する要素を+(プラス)で指定します。
HTML
<ul> <li id="first">テキストテキスト</li> <li id="second">テキストテキスト</li> <li id="third">テキストテキスト</li> <li id="fourth">テキストテキスト</li> </ul>
$(function() { $("#second + li").css("color","red"); });
id属性がsecondの要素の次に出現するli要素、つまり3行目のli要素が赤色になります。
これらのセレクターをどんどん使っていきたいと思います。
jQuery でセレクターの指定
先日jQueryでアコーディオンの制作をして記事を書いたのですが その前にセレクターの指定から書くべきだなと思ったので今回はjQueryのセレクターについて記載していきます。
HTMLのどの要素を操作するかをセレクターで指定していきます。 本編に入る前に本記事内で
$("セレクター").css("color","red");
このような記載の仕方をしますが[.css()]とはcssの[color]プロパティの値を[red]にするという意味になります。
1.要素セレクター
まずは簡単に要素セレクターから説明していきます。 HTMLはこのようになっております。
<ul> <li>テキストテキスト</li> <li>テキストテキスト</li> <li>テキストテキスト</li> <li>テキストテキスト</li> </ul>
こちらに
$(function() { $("li").css("color","red"); });
要素の[li]をセレクターで指定しますとli要素の部分全てが変更されます
2.IDセレクター
続いてはid属性をもつ要素を対象にします。
HTML
<ul> <li id="first">テキストテキスト</li> <li id="second">テキストテキスト</li> <li id="third">テキストテキスト</li> <li id="fourth">テキストテキスト</li> </ul>
id属性の値に#を付けたものをセレクターとして利用します。
$(function() { $("#second").css("color","red"); });
id値にsecondが設定されたli要素が赤くなります。
3.クラスセレクター
続いてはクラス属性をもつ要素を対象にします。
HTML
<ul> <li class="first">テキストテキスト</li> <li class="second">テキストテキスト</li> <li class="third">テキストテキスト</li> <li class="second">テキストテキスト</li> </ul>
クラス属性の値に.(ドット)を付けたものをセレクターとして利用します。
$(function() { $(".second").css("color","red"); });
クラス属性にsecondが設定された複数のli要素が赤くなります。
4.子孫セレクター
複数のセレクターをスペース区切りで指定することにより、特定の要素の中にある要素をさらに絞り込めます。
HTML
<ul> <li class="first"><p>テキストテキスト</p></li> <li class="second"><p>テキストテキスト</p></li> <li class="first"><p>テキストテキスト</p></li> <li class="first">テキストテキスト</li> </ul>
$(function() { $(".first p").css("color","red"); });
class属性がfirstで要素の内側にあるp要素だけが赤くなります。
といったところで一旦は終了したいと思います。 jQueryに関してはまだまだ勉強してブログを更新していく予定です
それでは
jQueryでアコーディオンの制作
アプリの制作をしていまして、アコーディオンを使ったメニューを制作したので手順等を記載いたします。
まずはHTMLは以下のように記載いたしました。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>アコーディオン</title> <script type="text/javascript" src="js/jquery-3.2.0.min.js"></script> <script type="text/javascript" src="js/menu.js"></script> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="menu"> <dl id="panel"> <dt>タイトル1</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> <dt>タイトル2</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> <dt>タイトル3</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> <dt>タイトル4</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> <dt>タイトル5</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> <dt>タイトル6</dt> <dd>コンテンツコンテンツコンテンツコンテンツ</dd> </dl> </div> </body> </html>
CSSは以下のようにしておきます。
.menu { border: solid #56df55; } .menu dt { background-color: #afeeee; } .menu dd { background-color: #e0ffff; }
この状態でブラウザ確認するとこうなります
こちらを「タイトル〇」と書かれた部分を押して「コンテンツ~」を表示するようにいたします。
jsファイルは以下のように作ります。
//メニューのアコーディオン $(function() { //デフォルトは全てのタイトルを非表示にします $('#panel > dd').hide(); //メニューのクリックを取得します。 $('#panel > dt').click(function(){ //クリックしたタイトルを開閉します $('+dd', this).slideToggle(200); }); });
これで「タイトル〇」と書かれた部分をクリックすると「コンテンツ~」が 表示されるようになります、もう一度「タイトル〇」を押すと「コンテンツ~」が閉じます。
それでは
CakePHP cssが反映されない時の対処方法
CakePHPでアプリの制作していてcssを編集してブラウザで確認した際に編集点が反映されていないという事があり、 原因を調べて対応したので手順等を記載いたします。
まずは原因ですが もしかしたらブラウザがcssをキャッシュしているのではないか? という記事がいくつかあったので、参考にいたしました。
解決方法としまして、app/Config/core.phpの中に
Configure::write('Asset.timestamp', true);
という一文がありましてコメントアウトされているのですが このコメントアウトを外したところ、ブラウザのキャッシュを無効化されて cssの編集が反映されました。
もし急にcssが反映されずに困ったら参考にしていただければ幸いです。
以下のサイトを参考にいたしました。
それでは
SQL サブクエリの扱い方について復習
SQLを書いていてサブクエリを使うのですが基本的な使い方のおさらいをしておきたいと思ったので記載いたします。
今回はデータうんぬんではなく、サブクエリを使う際の注意になります。
まず以下のようなサブクエリの使い方をしているとします
SELECT customers.name, ch.birthday, ch.number_of_purchases FROM orders INNER JOIN ( SELECT customer_histories.number_of_purchases, customers.name FROM customer_histories INNER JOIN customers ON customers.id = customer_histories.customer_id WHERE customers.birthday <= '1990-01-01' ) AS ch ON orders.customer_id = ch.customer.id WHERE orders.date >= '2017-05-01'
SQLの意味自体は一旦置いておいて、上記のSQLだとエラーが出ます。 原因は2つありまして、どちらも最初のSELECTの中にあります。
まず一つ目は [customers.name]です。 こちらエラーになる原因ですが、customersのnameがほしいんでしょうが customersの結合はサブクエリの中で行われています。書き方としましては サブクエリの最後に AS ch とあるので [ch.name]が正しい書き方になります。
続いて2つ目は [ch.birthday]になります こちらcustomersのbirthdayを表示仕様としているのですが サブクエリのSELECTにcustomers.birthdayがありません。 なのでbirthdayを呼び出せずエラーになります。 サブクエリのSELECTにcustomers.birthdayを入れるとオーケーです。
以下正しく修正したSQLになります。
SELECT ch.name, ch.birthday, ch.number_of_purchases FROM orders INNER JOIN ( SELECT customer_histories.number_of_purchases, customers.name, customers.birthday FROM customer_histories INNER JOIN customers ON customers.id = customer_histories.customer_id WHERE customers.birthday <= '1990-01-01' ) AS ch ON orders.customer_id = ch.customer.id WHERE orders.date >= '2017-05-01'
今までのブログでは特に書かずに進めていたところなのですが 結構エラーが出たり、質問されたりしたので一度まとめてみました。
それでは
SQL データの集計に関して
売上の計算をするSQLを制作していまして、特定条件で絞り込んだ顧客の初回購入から〇ヵ月間の売上を取得する という処理を制作したので、手順等を記載いたします。
まず前提として以下のようなテーブルがあるとします。
customersテーブル 顧客名 登録日(顧客として登録された年月日) +---+-------+-----------+ |id |name |created | +---+-------+-----------+ |1 |tanaka |2017-01-01 | |2 |yamada |2017-02-02 | |3 |satou |2017-03-03 | |4 |ito |2017-03-04 | |5 |katou |2017-02-05 | +---+-------+-----------+ customer_historiesテーブル 顧客id 注文日 購入回数 注文id 媒体id +---+------------+----------------+------------------+---------+---------+ |id |customer_id |date_of_purchase|number_of_purchase|order_id |media_id | +---+------------+----------------+------------------+---------+---------+ |1 | 1 |2017-01-05 | 1 |1 |1 | |1 | 1 |2017-02-05 | 2 |2 |1 | |1 | 1 |2017-03-05 | 3 |3 |1 | |1 | 2 |2017-04-01 | 1 |4 |1 | |1 | 3 |2017-05-01 | 1 |5 |1 | |1 | 4 |2017-06-01 | 1 |6 |1 | |1 | 5 |2017-07-01 | 1 |7 | | +---+------------+----------------+------------------+---------+---------+ ordersテーブル 顧客id 注文日 金額 +---+------------+--------------+--------------+ |id |customer_id |order_date | total_amount | +---+------------+--------------+--------------+ |1 | 1 |2017-01-05 | 100 | |2 | 1 |2017-02-05 | 200 | |3 | 1 |2017-03-05 | 300 | |4 | 2 |2017-04-01 | 100 | |5 | 3 |2017-05-01 | 100 | |6 | 4 |2017-06-01 | 100 | |7 | 5 |2017-07-01 | 500 | +---+------------+--------------+--------------+ mediasテーブル 媒体名 +---+--------+ |id |name | +---+--------+ |1 |blog | |2 |twitter | +---+--------+
まず条件として2つの軸で集計いたします。初回流入媒体と登録日です。 初回流入媒体ごとに分けて更に登録月別に分けます。 登録月別に別れた顧客の初回購入から3ヵ月間の購入の売上を計算します。 以下のようなSQLになります。
select ch.id as '媒体ID', ch.name as '媒体名', DATE_FORMAT(ch.created , '%Y%m') as '顧客登録月', FORMAT(count(distinct orders.customer_id),0) AS '顧客数', FORMAT(sum(orders.total_amount),0) AS '総売上' FROM orders INNER JOIN --サブクエリで初回購入のテーブルを作ります ( SELECT customer_histories.customer_id, customer_histories.date_of_purchase, medias.id, medias.name, customers.created FROM customer_histories INNER JOIN --登録年月日を出すためcustomersテーブルを結合します customers ON customers.id = customer_histories.customer_id INNER JOIN medias ON customer_histories.media_id = medias.id WHERE --初回購入の条件 customer_histories.number_of_purchase = 1 ) AS ch ON orders.customer_id = ch.customer_id WHERE --初回の注文年月から 2 MONTH つまり2ヵ月間のデータに絞り込みます DATE_FORMAT(orders.order_date ,'%Y%m') <= DATE_FORMAT(DATE_ADD(ch.date , INTERVAL 2 MONTH),'%Y%m') GROUP BY --まず初回流入媒体ごとに分けます ch.id, --次に登録年月ごとに分けます DATE_FORMAT(ch.created ,'%Y%m') ORDER BY --medias.idの昇順に並び替えます ch.id
上記のようになりまして結果は以下のようになります。
+-----------+------------+-----------+-------+--------+ |媒体ID |媒体名 |顧客登録月 |顧客数 |総売上 | +-----------+------------+-----------+-------+--------+ |1 | blog |2017-01 | 1 |600 | |1 | blog |2017-02 | 1 |100 | |1 | blog |2017-03 | 2 |200 | +-----------+------------+-----------+-------+--------+
確認すべき点は3つです。
まずは初回購入の媒体ごとに分かれている
登録月ごとに分かれているので登録月が3月の customers.id 3[satou]と4[ito]の2人が3行目で合算されています。総売上も合算されています。
購入時にメディアIDのなかった customers.id 5[katou]が分析に含まれていません。
続いてWHEREの[2 MONTH]を[1 MONTH]に変えてみます。 そうすると初回購入から2ヵ月間の売上を出力します。
+-----------+------------+-----------+-------+--------+ |媒体ID |媒体名 |顧客登録月 |顧客数 |総売上 | +-----------+------------+-----------+-------+--------+ |1 | blog |2017-01 | 1 |300 | |1 | blog |2017-02 | 1 |100 | |1 | blog |2017-03 | 2 |200 | +-----------+------------+-----------+-------+--------+
細かい違いですが、1行目の総売上が300になっています。 これは2ヵ月間の分析に変更したのでcustomers.id 1[tanaka]の3月の購入が 除外されたことが原因です。
これらが特定条件で絞り込んだ顧客の初回購入から〇ヵ月間の売上を取得するSQLになります。
それでは
SQL JOINの注意点について
初回購入商品ごとに顧客を出力して顧客たちの初回購入月の総売上を出力するSQLを作っていたのですが 問題点があったので記載いたします。
まず今回このようなデータが入っているものとします。
customersテーブル 顧客名 +---+-------+ |id |name | +---+-------+ |1 |tanaka | |2 |yamada | +---+-------+ customer_historiesテーブル 顧客id 注文日 購入回数 注文id +---+------------+----------------+------------------+---------+ |id |customer_id |date_of_purchase|number_of_purchase|order_id | +---+------------+----------------+------------------+---------+ |1 | 1 |2017-05-01 | 1 |1 | |2 | 1 |2017-05-15 | 2 |2 | |3 | 1 |2017-05-20 | 3 |3 | |4 | 2 |2017-05-02 | 1 |4 | +---+------------+----------------+------------------+---------+ ordersテーブル 顧客id 注文日 金額 +---+------------+--------------+--------------+ |id |customer_id |order_date | total_amount | +---+------------+--------------+--------------+ |1 | 1 |2017-05-01 | 100 | |2 | 1 |2017-05-15 | 500 | |3 | 1 |2017-05-20 | 300 | |4 | 2 |2017-05-02 | 100 | +---+------------+--------------+--------------+ order_detailsテーブル 注文id 商品id +---+---------+---------+ |id |order_id |item_id | +---+---------+---------+ |1 | 1 |1 | |2 | 2 |2 | |3 | 2 |3 | |4 | 3 |3 | |5 | 4 |1 | +---+---------+---------+ itemsテーブル(商品テーブル) 商品名 値段 +---+----------+-----+ |id |name |price| +---+----------+-----+ |1 |Pepper |100 | |2 |salt |200 | |3 |mayonnaise|300 | |4 |ketchup |400 | +---+----------+-----+
まず初めに以下のようなSQLを作りました サブクエリやDATE_FORMATやFORMATの使い方に関しては以前の記事を参考にしてください。
MySQLで特定期間のデータを抽出する - 情弱エンジニアのなかのblog
MySQLで日付に関する処理 - 情弱エンジニアのなかのblog
SQL小数点の表示とtimestamp - 情弱エンジニアのなかのblog
SELECT ch.name AS '商品名', FORMAT(count(distinct orders.customer_id),0) AS '顧客数', FORMAT(sum(orders.total_amount ),0) AS '1月間の総売上' FROM orders INNER JOIN ( SELECT customer_histories.customer_id, customer_histories.date_of_purchase, items.id, items.name FROM customer_histories WHERE date_of_purchase between '2017-05-01' and '2017-05-31' AND number_of_purchase = 1 ) AS ch ON orders.customer_id = ch.customer_id INNER JOIN order_details ON orders.id = order_details.order_id INNER JOIN items ON order_details.item_id = items.id WHERE DATE_FORMAT(orders.order_date , '%Y%m') <= DATE_FORMAT(ch.date_of_purchase , '%Y%m') GROUP BY items.id
こちらですと問題点として まず初回購入以外の商品データもGROUP BYの集計に入ってしまいます。
あとordersテーブルとorder_detailsテーブルを見るとわかるのですが、 order.id = 2で[tanaka]さんが同時に2つの商品を購入しているのでordersとorder_detailsの結合時に order.id = 2が2行分作られます。その状態で
select sum(orders.charged_amount)
をするとorder.id = 2 の total_amount = 500が2回集計されて間違ったデータになってしまします。
以下が正しい修正バージョンです。
SELECT ch.name AS '商品名', FORMAT(count(distinct orders.customer_id),0) AS '顧客数', FORMAT(sum(orders.total_amount),0) AS '1月間の総売上' FROM orders INNER JOIN ( SELECT customer_histories.customer_id, customer_histories.date_of_purchase, items.id, items.name FROM customer_histories INNER JOIN order_details ON customer_histories.order.id = order_details.order_id INNER JOIN items ON order_details.item_id = items.id WHERE date_of_purchase between '2017-05-01' and '2017-05-31' AND number_of_purchase = 1 ) AS ch ON orders.customer_id = ch.customer_id WHERE DATE_FORMAT(orders.order_date , '%Y%m') <= DATE_FORMAT(ch.date_of_purchase , '%Y%m') GROUP BY ch.id
今回の問題点は無駄な結合を行っていたことと、集計の軸を間違えていたことです。
それでは