SQLite3の提供する集約関数は avg, count, max, min, sum, totalが全てで、どれも数値を引数にとる。sumが与えられた数値の合計を返すように、与えられた文字列を全て連結して返す集約関数(MySQLの GROUP_CONCATがまさしくそれ)がないものかと探していた。それが無いなら無いで SELECT, JOIN, UNION, CASEといった標準的なものを使って、特定の列の値を(行をまたいで)連結したりできないものかと考えたけど、行と行の独立は破れなかった。
話は変わって、これ↓は昨日見つけた目から鱗ものの文書。
http://www.geocities.jp/mickindex/database/idx_database.html
対象読者として次のような項目が挙げられている。
- なぜ"関係"モデルという抽象的な用語を使うのか分からない。"表"モデルでいいじゃない。
- なぜ「= NULL」ではなく「IS NULL」と書かねばならないのか分からない。
- E.F.Codd、C.J.Date、J.Celko、F.Pascal の本を読んだことがない。
- IN述語とEXISTS述語では、IN の方が直観的に分かりやすいから好きだ。
- IN述語、EXISTS述語、LIKE述語・・・「述語」って何だ?
- テーブル設計のときは滅多に NOT NULL制約を付けない。しかもそれが大罪であることの自覚がない。
- SQL で CASE式を使ったことがない。
「INは使ったことあるけど EXISTSは知らない」「何故 = NULLと書いたものが IS NULLと同じ結果を返さないのか分からない」「 CASE?そんなんあった?」「DEFAULT '' は多用するけど、NOT NULLは付けてない。付けるべき理由があるなら知りたいよ」と、冒頭からがっちりハートを鷲掴み。
このサイトの文書がどれも興味深く、有用なのはさておいて、CASEの存在を今まで知らなかったことに少なからずショックを受けた。SQLiteの本家サイトにもちゃんと記述されているというのに。(→Query Language Understood by SQLite: expression)
そこで改めて SQLiteでできることをおさらいしてみたところ発見されたのが create_function。(→C/C++ Interface For SQLite Version 3)
C/C++ APIだから Rubyから使うには dl を使わなあかんのかと思ったら、何と SQLiteといつもセットで利用しているsqlite3-rubyの SQLite3::Databaseオブジェクトにはその名も create_aggregateなんてメソッドが存在するのですねえ。一体今までどこに目を付けていたのかと……。
そんなわけで、無いなら作ってしまえ文字列連結集約関数〜♪。
require 'sqlite3' database = SQLite3::Database.new('hoge.db'); # concatという不定数の引数をとる集約関数を作成。 # 第一引数(val)は連結される文字列。 # 第二引数(sep)は valと valの間に挿入されるセパレータ。 # 第三引数(sortval)は valを連結する前に並び替えたい場合にソートキーとして利用される文字列/数値。(省略されたり NULLの場合はソートしない) # 第四引数(desc)はソートの昇順/降順を切り替える。(省略/NULL=>昇順, その他=>降順) database.create_aggregate(name='concat', arity=-1){ step {|func, val, sep, sortval, desc| func['separator'] = sep.to_s; func['sortdesc'] = !(desc.nil? || desc.null?); func['needsort'] = (func['needsort'] || !(sortval.nil? || sortval.null?)); func['sortvaltype'] ||= (sortval.nil? || sortval.null?) ? nil : {:int=>:to_i, :float=>:to_f, :blob=>:to_blob, :text=>:to_s}[sortval.type]; func['array'] ||= []; func['array'].push([ (sortval.nil? || sortval.null?) ? nil : sortval.send(func['sortvaltype']), val.to_s ]); } finalize {|func| arr = (func['array'] || []); arr = arr.sort_by{|x| x.nil? ? {:to_i=>0, :to_f=>0.0, :to_s=>''}[func['sortvaltype']] : x.first.dup } if(func['needsort']); arr.reverse! if(func['sortdesc']); func.result = arr.map{|x| x.last }.join(func['separator']); } }
というわけで、探し物が見つかったということに満足しつつ、文字列の連結は集約関数でなく ERBスクリプトで行っている現在。
データベースに対するリードオンリーアクセスを保証したりもできるのねん。
CGI経由で渡された SQLも安全に実行できそうじゃね?
#!ruby -T4 eval(ENV['QUERY_STRING'])
と同程度かそれ以上に。
http://www.sqlite.org/capi3ref.html#sqlite3_set_authorizer から引用しておく。
The intent of this routine is to allow applications to safely execute user-entered SQL. An appropriate callback can deny the user-entered SQL access certain operations (ex: anything that changes the database) or to deny access to certain tables or columns within the database.
layout.word_select.eat_space_to_next_word = false
Windows版ではデフォルトで trueらしい。でも今回 探してた設定はコレ↑じゃなくて、画像を読み込めなかった時に表示される altテキストを(画像と同じ)置換要素として表示する方法。
画像を表示できなくて altを表示する場合でも IEのように widthと height属性*を尊重して欲しいわけ。widthが無効でその上 改行(
)も有効でないと来たら、どうやって折り返したらいいの?
HTMLはいじらない。CSSで解決するなら
img { display: inline-block }
となりそうだが inline-blockは CSS2.1で追加された値なので Firefox1.5は未対応。どうしたらいいの?
* 非置換インライン要素に width, height属性は適用できない。
こんなこと書いたけど結構 6も 7も楽しんだんだよね。6は偶数作品らしく多数の、名前とストーリーを持ったキャラが魅力だし、戦闘もアクセサリの組み合わせが楽しかった。7のマテリアは、6で 2つまでしか装備できなかったアクセサリが 4組 8つまで装備できるようになったようなものだから当然あれやこれやと組み合わせを考える楽しみは尽きなかった。
8*は闇に葬って、
改めて 9をプレイすると至極真っ当なファンタジーをしてることに(2回目のプレイで)気付く。
境遇の違うジタン、ダガー、ビビ、スタイナーは旅をしながらそれぞれの生き方を模索し、成長していく。こんな王道のストーリーが今は気持ちいい。
ジタンとダガーの近づきそうで進まない仲と、二人の関係を冷静に観察しつつジタンにアタックするエーコと、いつの間にかエーコに子分のように扱われているビビの関係は微笑ましくて、見ていて本当に楽しい。
終盤になるとこちらの攻撃をトリガーにしてアクションを起こす敵が非常に多くなってイライラさせられた記憶があるが、今なら、打撃でカウンターが発生するなら魔法と召喚で攻撃するだけの余裕がある(と思う。まだ終盤に届いてない)。
* 陰気な?退屈な?思い出せないストーリー。新システムを作るために作られた面倒くさいだけのシステム、ジャンクション。キスティス先生だけが俺の楽しみだったよ。
HKEY_CURRENT_USER\Software\Classes\Applications\hoge.exe\shell\open\commandか、あるいは HKEY_LOCAL_MACHINE\Software\Classes\Applications\hoge.exe\shell\open\commandの下にある、(既定)の文字列値が存在しない場所の hoge.exeを指しているかもしれない。hoge.exeを移動したなどの理由で。
大雑把に hoge.exeとその下のキーを全て削除するも良し、(既定)の文字列値を正しいパスに書き換えるも良し。(zipファイルを SUSIEで開こうとして何度 SUSIEを参照しても一覧に表示されなくて、この二、三日困っていたのだよ)
FFは腐ったアクティブタイムバトル(ATB)*に嫌気がさして 9までしかプレイしていなくて、12に関しても発売日が過ぎてから公式サイト⁑をのぞいてみるような扱いだったのだけど
エグゼクティブプロデューサー 河津秋敏⁂
原案/シナリオプロット/監修 松野泰己*4
というのを見て |д゜)をっ
Final Fantasy XII が最高すぎる件を読んで (*´д`*)ハァハァ
10月16日に書いたように聖剣LOMをクリアして、12月13日頃から FF12をプレイしている。
そうしたら聖剣LOMで一番良かった珠魅編を担当していた生田美和氏が FF12でもシナリオに関わっていた。
DiscWizard2003を使って Cドライブの中身をまるっとコピーして終い。
xcopyだと細かくオプションが指定できるのだけどレジストリやプライベートなファイルなどコピーできないファイルが多い。
DiscWizard2003でコピーした後で xcopyで上書きコピーすれば最大限に情報が保存されるだろうか。
Windows2000/XP Proのみがサポートするダイナミックディスクには、普通のパーティションの他にミラーリング/ストライピング/RAID5なパーティションが「ディスクの管理」ユーティリティを使って作成できる。
20060304p01の続き。
ファイルのリカバリのために再起動を繰り返してたら突然問題の HDDが BIOSから認識されなくなったので、てっきり HDDがスクラップになったんだと思ってたがそうではなかった。なんか SATAコネクタに問題があったみたい。
問題の HDDと Windowsの入った正常な HDDを入れ替えたら今度は Windowsの入った HDDが BIOSで認識されなくなった。SATAケーブルを何度か抜き差ししてたら両方の HDDが認識されるようになった。
ファイルシステムが壊れてることに変わりはないのでファイルのサルベージは必要だけどデータが 100%失われることに比べたら 20や 30や 40のファイルが失われることがなんだってんだ。
こうなるとファイルが壊れたりファイルシステムが壊れたりしたのも SATAコネクタが断続的に繋がったり切れたりして書き込みが正常に完了しなかったせいかもしれない。Maxtorを疑って悪かったよ。
昨晩注文して明日到着予定の HDT722525DLA380(日立IBM SATA2 250GB)と ST3250824AS(Seagate SATA2 250GB)を接続する場所がなくなってしまったのはどないしょ。250GBの HDD 3つで RAID5*でもする?
* 250GBの HDDが 3つで 750GB。その内、250GB*(3-1)=500GBを記憶域として利用でき、3つの内のどの一つのディスクが壊れてもデータが失われない。RAID1(ミラーリング)より容量の面で有利。
この前、ファイルが無くなって Windowsが起動できなくなったのとは別の HDD。
最初はトレイアイコンから、ファイルが壊れてて読み取れないってメッセージが表示された。空き領域が 30GBと表示されている。最近は空き領域の確保に苦労していたので 30GBは多すぎる。
CHKDSKを試したがどういうわけか開始しない。とりあえず再起動。
問題の HDDに張っていたマウントポイントが解除されて E:\として見えている。ボリュームラベルもデフォルトに戻っている、どころか空き領域が 233GB。未フォーマットって何じゃ。どうやら、ファイルシステムが NTFS5.1だということが分からなくなった様子。
PC Inspector File Recoveryというソフトをダウンロードして試す。エクスプローラでは既に表示できなくなった、E:\ 直下に存在するはずのフォルダが表示されて何とかなりそうな雰囲気。
でも、このソフトを操作してると PCが突然再起動したりする。
さっき 4回目の再起動に遭遇した。E:\ はもう無い。
ファイルシステムがどうのという以前に HDDが HDDとして認識されなくなってしまった。
こうなるとファイルのサルベージとか考える必要もなくって、いっそ清々しいね (´Д⊂グスン