jquery.ajaxに代わる、Fetch APIについて

Facebook にシェア
Pocket

最近のJavaScriptでは、jQueryに依存しない書き方が増えてきたようです。ただ、確かにセレクターなら、document.querySelectorAllメソッドを使えばいいだけなんですが、個人的にjQueryで便利なところは、ajaxだと思ってるんです。いちいち、XMLHttpRequestがどうちゃらこうちゃらとか書きたくないし、だいいち覚えられない。だから自分は、jQueryからはなかなか離れられないだろうし、離れたとしてもAjaxようの共通関数は実装することになるんだろうなぁ。と思っていたら、最近になってFetch APIなんてものを知りました。

最近のWeb技術界隈は追えていないと思ったらこんなものが。というわけで、調べて使ってみました。

HTML

PHP

サンプル:Document

やってることは、サーバーに数値と文字列をPOSTで渡すと、数値を2倍、文字列をSHA-256でハッシュ化した結果をJSON形式で返すというもの。例えば、数値を123、文字列をabcとすると下記のようになりました。

確かに数値は2倍になって、文字列はハッシュ化して返ってきました。ちょっとよく分からなかったのが、最初にResponseオブジェクトからどういう形式で値を取得するかという指定が必要なこと。これがPromiseオブジェクトで返ってくるので、いちいちthenを二回書かなきゃいけないという。response.json()で返ってくる値がPromiseオブジェクトじゃなくて、JSONオブジェクト(多重表現)になってるほうが直感的でわかりやすい気がするのだけど、多分、こうなってるメリットはあるんだろうと思う。このへんは多分、自分がPromiseについてよく分かってないから疑問に思ってるのだと思うので、もう少しこのへんも勉強していこうと思う。

ところで最初、fetchのbody部分を「body: new FormData(document.getElementById(‘frm’))」と指定しようと思ったのですが、それだといまいちメリットがないなと思ったら、JSONで渡せることを知ったのでそうしました。PHP側で『json_decode(file_get_contents(‘php://input’), true);』とすればいいそうです。初めて知りました。JSONのまま渡せるなら、便利ですね。これからはそうしようかな。

【SQL】特定のデータがあるグループのみ抽出する方法

Facebook にシェア
Pocket

SQLで集計する時に、ある特定の値があるグループのみ抽出したいということがあると思います。先日、仕事でそういうことをしたいということがあったのですが、すぐには思いつかず、仕事を終えた後に思いついたので、紹介したいと思います。

今回、使うのは下記のようなサンプルテーブル。テーブル名はtest1で、フィールドがグループ番号、名前、年齢、点数とします(名前と年齢は今期見てるアニメからとっています)。

ここから、中学生(12~14歳)がいるグループのみのグループ番号と平均点を取得するSQLを取得するには下記のようにすればとれます。

上記の結果が下記です。

確かに、グループに中学生のいる1と2のみの平均点が表示されました。

上記のSQLは何をしているかというと、まずはGROUP BYで全データを集計し、HAVINGで12~14歳の年齢がいるグループのみに絞っています。

なぜ、これで絞れるかというと、CASEの条件(ここでは「age BETWEEN 12 AND 14」)に一致した値があれば1という値が含まれ、無ければ0しかないということになるからです。それぞれの行にCASE文の結果を付与すると下記のようになります。

そこからMAX関数で最大値をとってくるので1が含まれていれば1、1が含まれていなければ0となるので、1に等しい値を抽出した結果、条件に一致したグループのみを取得できることになります。

逆に、特定のデータが入っていないもののみを抽出したいという場合は、「= 1」の箇所を「<> 1」とするか、「= 0」とすることで、取得することができます。

なお、HAVINGを使わなくても、サブクエリーを使うことで同じことができます。

ただ、HAVINGを使ったほうがシンプルなので、基本的にはHAVINGを使ったほうがいいと思います(実行計画のコストも、HAVINGを使ったほうが少しだけ低いようです)。

HAVINGは今までほとんど使ってこなかったのですが、使い始めると結構便利なことに気づきました。いろいろ応用もできそうなので、使いこなしていきたいです。

2018/03/26追記:そういえば、この記事を書こうと最初に思ったときは、条件は中学生以下、つまり「MAX(CASE WHEN age <= 14 THEN 1 ELSE 0 END) = 1」にしようとしていました。ただ、これだと、「MIN(age) <= 14」でもいいことに気づき、中学生が含まれるかどうかという条件に変更しました。こういう条件は、シンプルに考えられるようになりたいです。

外部結合したテーブルの値で内部結合するなという話

Facebook にシェア
Pocket

最近、仕事では複雑なSQLばっかり書いています。

ただ、今関わっているプロジェクトでは上から設計書を渡されてそれをコードとして書くのですが、SQL部分はほとんどそのままで、違うのはテーブル名やフィールド名が日本語になっているぐらいという感じです(場合によっては、効率が悪かったり、ムダにSQLを分けているなと思うと、こちらで書いて後から設計書に反映してもらうこともあります。変更が大きかったりすると嫌がられてるのが伝わってきます)。

そんな中で出てきたコードが下記のようなコード。自分も書いてるときは何も思わずにそのまま書いてしまっていました。

問題です。table1のsubid(ここでは1とする)に対応するtable2のidが見つからない場合、結果はどうなるでしょう。

答えは、

id field
1 null

とはなりません。

なぜなら、table1のsubidに対応するtable2がないのだから、内部結合しているtable2に対応するtable3もないから。で、外部結合だと対応する値が無くても出力しますが、内部結合だと対応する値が無いと出力しないので、結果、出力しないことになります。

なので、上記のSQLはtable3の結合も内部結合として、

とするのが正解なはずです。多分、table1にあってtable2に対応する値が無いことはあるけれど、table2にあって対応する値がtable3に無いことは無い(絶対にある)ので、こういうSQLを作ってしまったんだと思います。

ところで、今のプロジェクトで使っているDBMSはDB2の10.1なのですが、上記のようなSQLにおいて、なぜかWHERE句にANDを追加すると値が出力されるのだけど、無いと出力されないという摩訶不思議な現象が発生しました(ANDを使って条件を追加すると、通常は結果が変わらないか少なくなるはず)。

いろいろ調べてみると、上記のように結合部分がおかしかったので修正したら直りはしたのですが、なぜこんな現象がでたのかは謎です(条件の部分に関しては、上記の結合箇所は全く関係無かったし)。DB2のバグっぽいのだけど、そういう現象って報告されてたりするのだろうか。条件によってでたりでなかったりしたので、再現方法はわからないのだけど。

画面内に入ったり出たりした時の処理を行う「Intersection Observer」について

Facebook にシェア
Pocket

先日、超速! Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)という本を読んで知ったのですが、最近のWebブラウザのJavaScriptには、「Intersection Observer」というAPIがあるらしく、このAPIを使うことで画面内に入ったか(もしくは画面外に出たか)どうかを判定できるそうです。

便利そうなので、試しに使ってみました。画面に四角い要素を100個並べて、画面に入ったり出たりすることで背景色が変わるサンプルです。試しに、今まで知ってはいたけど使ったことがないCSSアニメーションや、ES6から実装されたletやconstやアロー関数も使っています。

HTML

CSS

JavaScript

サンプル:Intesection Observeテスト

スクロールしたり画面サイズを変更したりすることで、四角い要素が画面内に入ると、背景色が1秒かけて青からオレンジに変わると思います(IE以外の最新ブラウザ対応)。

ただ、すばやくスクロールしているとたまにうまく動作しないことがあるみたいです。あまりアテにしすぎるのもよくないのかも(自分がよく分かってない可能性もおおいにあります)。

なお、IntersectionObserverの第2引数にはどの要素の交差を判定するか(なければブラウザのビューポート)のrootと、ルート回りの余白を指定できるrootMargin、それと可視性がどれぐらい入ってるか出ているかでコールバックを実行するthresholdというオプションがあるそうです。
参考:Intersection Observer API – Web API インターフェイス | MDN

超速!  Webページ速度改善ガイド ── 使いやすさは「速さ」から始まる (WEB+DB PRESS plus)
佐藤 歩 泉水 翔吾
技術評論社
売り上げランキング: 11,340

JavaScriptで日時の加減算を行う

Facebook にシェア
Pocket

またもや、改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用までから。

JavaScriptの日時処理は少し面倒だという印象があります。上で紹介した本を読んでも、ES2015でもそれは変わってないらしく、例えばフォーマットによる日時を付与した関数なんてものも用意されてないらしいです。

その点ではMoment.jsというライブラリ(参考:Moment.jsを使う – Qiita)がよさげではあるのですが、今回は素のJavaScriptを使った加減算について。

というのもやり方は簡単で、DateオブジェクトのgetXxxxxメソッドとsetXxxxxメソッドを使えばいいだけだそう。実は、本をよむまで、getとつくメソッドがあるのは知ってたけど、setとつくメソッドがあるのは知らなかった。

使い方としては以下。

見て分かるように、月をまたいでもちゃんと計算される(それにしてもなぜ、月だけ0始まりにしたのだろうか。最初間違えて、『new Date(2016,11,6,22,30);』として12月6日になって混乱した)。

これを応用したら、指定の日付の月末日を取得することができる。

ちなみに、setXxxxメソッドの戻り値は、Dateオブジェクトではなくて1970 年 1 月 1 日 00:00:00 からのミリ秒数。Dateオブジェクトだったらメソッドチェーンが利用できたので少し面倒。まあ、目的は変更後の日付を返すのではなく、自分自身の日付を変更するということだから仕方ないか。

まあ、やろうと思えば下記のようにできなくはない。

いや、これはメソッドチェーンとは言わないか。

というよりよくよく考えたら、Dateオブジェクトを新しく生成すればいいだけでした(調べて気づいた)。

なお、日付通しの計算については、getTimeメソッドを利用して数値化したうえで、1単位をミリ秒数で表した数で割らなきゃいけないそうです。

なんで標準でこれぐらいの計算が簡単にできるメソッドが用意されていないのだろうか……。ES2015では追加されるんじゃないかと期待していたのだけど……。