ねこものがたり

いちにちいっぽ

RailsとSQLでわちゃわちゃやってます

自分の課題

DBから前後のデータをとってくる - ねこものがたりの続きをやっていて感じた自分の課題。

  • 複雑なSQLの操作に慣れていない、間違えたり調べたりしてなんとかやってる
  • railsのコードとSQLが自分の中で一致してない(単独でやると操作できるけど相関関係の理解が抜けてる)
  • railsのコードもそもそもそんなに慣れてない。試行錯誤の末長くなったコード。やっとここまできただけで満身創痍。さらにきれいに書くなんてレベルが高い。だがここで倒れたら死ぬと思え(とは言われてない)。

課題に対する策

この課題を踏まえ、またFjordでもらったコードを考えるためのアドバイスをもとに

" .to_sqlで書いたコードがどんなSQLになるか確かめる"

を毎度やることで自分の中に定着させていくことにしました。

考えるときのドキュメント等については以下の3点を参照しています。

Ruby on Rails APIのActrive Record::Query Methodsのところ

Active Record クエリインターフェイス | Rails ガイド

改訂第3版 すらすらと手が動くようになる SQL書き方ドリル:書籍案内|技術評論社

1度分かったと思っても本当に理解してないとすぐに抜けてしまうので、また簡単なところから考えるというのを積み重ねる感じです。(なので今後も継続する)

やってみた

コードがどんなSQLになるか確かめる

前回のコードの一部。

def previous
  Report.order(created_at: :desc).where(user_id: user_id).find_by("created_at < ?", created_at)
end

このメソッドに"同じuser_idとcreate_atをもつレコードが複数あればidが小さいもの"を検索するコードを追加したいと思います。

まず"同じuser_idとcreate_atでidが小さいレコード"で考えました。

最初に書いたコード。

Report.order(created_at: :desc).order(id: :desc).where(user_id: report.user_id).where("created_at = ?", report.created_at).find_by("id < ?", report.id)

SQLに変換する。

$ Report.order(created_at: :desc).order(id: :desc).where(user_id: report.user_id).where("created_at = ?", report.created_at).find_by("id < ?", report.id).to_sql

-> Report Load (0.9ms)  SELECT  "reports".* FROM "reports" WHERE "reports"."user_id" = $1 AND (created_at = '2017-01-02 00:00:00') AND (id < 312758158) ORDER BY "reports"."created_at" DESC, "reports"."id" DESC LIMIT $2  [["user_id", 459775584], ["LIMIT", 1]]

一応できた。(きれいにするのはあと)

コードを書き直す

Report.order(created_at: :desc).where(user_id: user_id).find_by("created_at < ?", created_at)


Report.order(created_at: :desc).order(id: :desc).where(user_id: report.user_id).where("created_at = ?", report.created_at).find_by("id < ?", report.id)

次は、この2つを1つのpreviousメソッドに収めたい。

最初はこう書きました。

def previous

reoport = Report.order(created_at: :desc).where(user_id: user_id).find_by("created_at < ?", created_at)

if report == nil

Report.order(created_at: :desc).order(id: :desc).where(user_id: report.user_id).where("created_at = ?", report.created_at).find_by("id < ?", report.id)

report

この時点で1度レビューを受けましたが、いろいろだめでした。

  • 方針が違う
  • .orderや.whereなどを繰り返していて書き方が良くない
  • Active Recordの使い方が良くない というのがありました。

方針の違いはここではおいておいてActive Recordはメソッドが長い、複雑なものほど処理に時間がかかり重くなるので注意が必要だそうです。

私が書いたコードは
「1回検索する→見つかる」
ならすぐに処理完了となりますが
「1回検索する→nil→もう一度さっきとちょっとだけ違う条件で全部検索する→見つかる(見つからないかも)」
となり下手するとめちゃくちゃ遅くなるので、処理の結果がたとえ同じでも遅い時点で良くない。

なのできれいなコードにするのと同時に、以下のようにしました。

def previous
  Report
    .where("user_id = ? AND created_at = ? AND id < ?", user_id, created_at, id)
    .or(Report.where("user_id = ? AND created_at < ?", user_id, created_at))
    .order("created_at DESC, id DESC")
    .first
 end

いきなりすごい変わった!!!!

SQLに変換するとこう

$ Report.where("user_id = ? AND created_at = ? AND id < ? ", report.user_id, report.created_at, report.id).or(Report.where("user_id = ? AND created_at < ?", report.user_id, report.created_at)).order("created_at DESC, id DESC").first.to_sql


->SELECT  "reports".* FROM "reports" WHERE ((user_id = 459775584 AND created_at = '2017-01-02 00:00:00' AND id < 312758158 ) OR (user_id = 459775584 AND created_at < '2017-01-02 00:00:00')) ORDER BY created_at DESC, id DESC LIMIT $1  [["LIMIT", 1]]

ここに至るまでに、複数条件の書き方がうまくできなかったり、論理演算子と戦ったりして、本当はめちゃくちゃ時間がかかりました。

しかもまだこれで本当にOKかどうかはわからないというw

だけどあーでもないしこーでもないしとやっているうちに少し「自分の中でわかってきたな〜」と思いました。

その他

今回やってみたのはSQL変換ですが、ほかにも「GUIツールを使う」というのも教えてもらいました。

やらなかったのはとりあえず.to_sqlのほうが手っ取り早いと思ったのと、ツールを使ったことがなかったので最初はどう操作しても確実に誰にも迷惑かけないし大丈夫そうなやつで練習したいと思ったからですww

今自分のアプリを作ったりしてるので近々使ってみようと思います!

今後続けていくこと

最初に書いた
* .to_sqlで書いたコードがどんなSQLになるか確かめる

以外に

  • SQLの復習をすること(1度ちゃんとやったけど曖昧):書籍をもう1周中
  • rubyのメソッドrailsのメソッドを理解する:とくにapi.rubyonrails.orgに書いてあるようなこと、とりあえず読もう

この3点が今の自分にすぐできることかな〜と思っています。 他にもあれば教えてほしいです。

今もまだ若干混乱してますがActive RecordまわりのことSQLのことを自分に定着させていきたいです!

トラウマなんかに負けたくないっていう話

過去の仕事での辛い出来事がなかなかにたくさんあります。

特に初めて転職して入った会社(IT関係でも何でもないけど名の知れた会社)がかなりひどくて、日常的にモラハラパワハラ、セクハラ等いろいろありました。

辞めてから数年経ちますが、ふと取り憑かれたように思い出してしんどくなることがあります。

今日、そんな感じでしんどかったです。

調べるとこんな記事がすぐ出てきました。

退職後トラウマに陥らないために - 職場のモラル・ハラスメント対策室職場のモラル・ハラスメント対策室

これを読んで「あ〜そうか、わたしトラウマになってるんだ」って思いました。(気づくのが遅い)

あんな環境に無理して居続けなくて本当に良かったと心から思います。 同時に”ちゃんと区切りをつけてもう引きずりたくない”とも。

ただ、今日思い出した時に”今までと自分変わったかも”って思いました。

思い出すのは過去に言われた言葉がほとんどです。 そしてその言葉がそのとおりに思えて「私は耐えられなかった弱い人間」「他の人のように優秀ではない使えない人間」と、自分を自分で貶めるような思考になりがちでした。

でも今日は「弱かったかもしれないけど少なくとも今は違う」「私はちゃんと頑張っている」「人がどうかなんか関係ない」「私は優秀じゃないかもしれないけどやっていける」って思いました。 (過去言われたことに対して反論する感じ)

少しずつ区切りをつけられてるのかな〜

私は基本的に自分に自信がありません。 足りないから過去のことにとらわれてしまうのだと思います。

もっと自信がほしい。 私にとって今やっていることは自信をつけることにつながって、自信をつけることは過去の自分を助けることにもなるんだと感じました。だからこの記事にしました。

プログラミングは純粋に楽しい。 楽しいからやっているしプログラマーとして就職したいと思ったし、始まりはそうでした。

だけど今日こんな自分自身のためにも絶対にやっていこうという気持ちが強くなりました。