mysql テーブル設計 カンマ区切りのカラムについて考察
例えば商品の属性とかレコードに紐づくデータが沢山あってレコード毎にデータ作ると色々面倒なケース。
DB設計の基本について 例えば一つのレコードが複数のカテゴリに… - 人力検索はてな
MySQLでカンマ区切りの値を登録してみる | シスデイズ技術ブログ
まさにこういうケース。基本はやはり忠実に正規化するのがベターらしいが、場合によってはカンマ区切りにするのもあり。ただカンマ区切りにしてしまうとjoinが面倒になるぽい。柔軟なのはやはり正しく正規化する方なんだと思う。
正規化した場合の問題について
まず正規化した場合、上の例でいうとAカテゴリとBカテゴリに属するレコードを取得する(AのみBのみは除く)となった場合、一番シンプルなのがgroup_concatでカンマ区切りにした結果に対してfind_in_setで絞り込む方法では無いかと思う。
しかし他のテーブルと結合したいと(group_concatでgroup byしてさらにの他のテーブルのカラムでgroup byしたい場合等)なった場合、いったんgroup_concatして、その結果を副問合せとかで結合、という手順を踏まないといけなくなるため、最初からカンマ区切りのデータであればその辺がシンプルになるはず。
データが膨大な場合は、「いったんgroup_concatして」すら出来なくなると思うので、最初からカンマ区切りならそのまま別テーブルと結合して、別テーブルの条件で絞り込んだデータに対してfind_in_setをすれば良い訳だから、データ量によってはパフォーマンスが圧倒的に変わると思う。
とはいえjoinが出来ない(面倒な)のも痛いしな~、両方用意して使い分けるのもありかもしれんけどな。片方更新したらもう片方も更新しないといけないから、その辺は覚悟せなあかんくなる。
全ての要件を満たす方法が無いとなると、後は何を優先させるかだな。パフォーマンスなのか開発工数なのか保守性なのか。ただ絶対に守らないといけないことが1つあって、それは「シンプルである」ということ。これだけは絶対に外してはいけない。
よく考えた結果、テーブル結合が発生する場合は副問合せはどうしても必要になるけど、サブクエリにするタイミングをずらすことで正規化でもパフォーマンス落とさずにできるかも。もうちょっと検証してみる。
結論
自分のSQLがダメだっただけで、やっぱり正規化でパフォーマンス落とさずに対応することができた。なので正規化のデメリットはデータ数が増えることくらいではないかな。でもそれはシステム化すれば大した問題ではない。なのでカンマ区切りにはやっぱりしないこと。
資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html
cakephp1.2 database.phpのdefaultに設定されているDBのテーブルはModelファイルの作成が必須ではない
ClassRegistry::init('ModelName');
こんな感じでmodelsフォルダに存在しないModelを読み込んでいた場合に、何故かエラーになる場合とならない場合があって1時間くらいはまってしまったのでメモ。
どうやらdatabase.phpで$defaultに設定されたDBのテーブルだとModelファイルが無くてもエラーにならないっぽい。(もちろん実際のテーブルが存在しなかったらエラーになるが。)
defaultのDBであればModelファイルが無くともfindとかも普通に使える。
今までModelファイルが必須だと思い込んでいたのでもう二度と忘れないこと。
php sqlのIN句をarray_fillでキレイにまとめる
以下のようにすれば一行で$idの数だけ?を記述するin句が作れる
i.id in ('. implode(',', array_fill(0, count($id), '?')). ')
str_repeatを使う方法もあるようだけどこっちの方がキレイ
cakephp1.2 通常のSQLとO/Rマッパーとのselectの結果の違い
今更だけどメモ。cakephpでO/Rマッパーというかfindとかした時の結果と、通常のsql(query)を実行した時の結果の違いについて。
$sql =<<<SQL select * from users u inner join posts p on p.user_id = u.id where u.id=1 SQL; pr($this->User->query($sql));
結果
Array ( [0] => Array ( [u] => Array ( [id] => 1 [user_name] => ユーザー1 ) [p] => Array ( [id] => 1 [post_date] => 2016-11-19 ) ) [1] => Array ( [u] => Array ( [id] => 1 [user_name] => ユーザー1 ) [p] => Array ( [id] => 2 [post_date] => 2016-11-20 ) ) )
O/Rマッパーを使用した場合
sql
$this->User->bindModel(array('hasMany'=>array('Post'))); pr($this->User->findById(1));
結果
Array ( [User] => Array ( [id] => 1 [user_name] => ユーザー1 ) [Post] => Array ( [0] => Array ( [id] => 1 [post_date] => 2016-11-19 ) [1] => Array ( [id] => 2 [post_date] => 2016-11-20 ) ) )
こんな感じでO/Rマッパーを使うと、重複しているUserデータが統合されることで結果がスマートになるという違いがある。
ただ通常のSQLの場合でもGROUP_CONCATとか使えば重複を省くことが可能。
資産形成におすすめのFX口座はこちら。
http://s2fx.com/ranking/856.html
mysql group_concatとfind_in_setのまとめ
group_concatはgroup byで複数行をまとめた際に、まとめられた列のデータをカンマ区切りで表示する機能。
find_in_setはカンマ区切りのデータを絞り込む機能。
この2つを組み合わせることで、本来なら副問合せ等の複数のSQLに分けないと出来ないようなことが一つのSQLで完結できることが分かった。
ただ速度的なメリットがあるのかどうかは不明。
参考ページの例を使うと以下のようなsqlでmarketとsalesに所属するempを一発で取得できる。
select dept_emp.empid, emp.name, GROUP_CONCAT(dept.name order by dept.id) as dept_n from dept_emp left join emp on dept_emp.empid=emp.id left join dept on dept_emp.deptid=dept.id group by dept_emp.empid having find_in_set('market', dept_n) and find_in_set('sales', dept_n);
結果
+-------+-------+------------------+ | empid | name | dept_n | +-------+-------+------------------+ | 3 | smith | market,hrm,sales | +-------+-------+------------------+ 1 row in set (0.00 sec)
参考ページ
GROUP_CONCAT関数の便利さは異常 - 開発の風景 〜KKZのSE日記〜
MySQL :: find_in_set() 関数 [Tipsというかメモ]
商品とそれに紐付けされた複数のカテゴリ情報を一つのSQLで取得する - Qiita
bootstrap ハンバーガーメニューを常に表示する方法
bootstrapのハンバーガーメニューをどのサイズでも常に表示させたい場合
Customize and download · Bootstrap
@grid-float-breakpoint
=> 9999pxとか大きい値にする
※9999とか気持ち悪いんだけど他に方法が無さそうだったので仕方なくこうする
widows8.1でIonic1.3のサンプルアプリをブラウザとandroid端末で動作させる手順
windows8.1環境で確認
Getting Started with Ionic - Ionic Framework
こちらの手順に従う
https://nodejs.org/en/
node.js v6.9.1 インストール
コマンドラインで実行
npm install -g cordova ionic
(終わるのに15分くらいかかる)
ionic start myApp tabs
pcでの動作確認
ionic serve --address localhost
androidでの動作確認
ionic platform add android
エラーが起きたので以下環境変数を設定
ionic build android
以下エラーが発生したのでJAVA_HOMEの最後のbinを削除
ERROR: JAVA_HOME is set to an invalid directory: C:\Program Files\Java\jdk1.8.0_45\bin
(終わるのに10分くらいかかる)
android端末をpcに繋げる
ionic run android --device
licenses関連でエラーになった。sdkをアップデートしないといけないかも。pcから見れたのでいったん諦める。