[[SQlite3を使ってみる。]] - [[Ruby]]
sqlite3って、データ型が以下しかないんですって。
,TEXT,テキストデータ
,NUMERIC,数値
,INTEGER,整数
,REAL,小数点などを含むリアル値
,NONE,形式なし
データを格納する時には以下が要注意ですって。
- TEXT型のカラムにINTEGERやREALのデータ型の値が格納された場合、TEXT型に変換されてから格納される。
- NUMERIC型のカラムにTEXT型の値が格納された場合、INTEGER型またはREAL型に変換を試みる。成功すればそのデータ型で格納されるが、失敗すればTEXT型のまま格納される。
- INTEGER型のカラムに整数化できるREAL型の値(12.0など)、また同じ形式のTEXT型の値が格納された場合、INTEGER型に変換して格納する。
- REAL型のカラムにINTEGERの値が格納された場合、REAL型に変換して格納する。
- NONE型は変換しない。
まぁ形式はなるべく守るべきよね。
ところで上を見ればわかると思うけど、時制を入れる先がないのよね。悩んだ末にこんな題材を作って見たの。
* 演習「NHKニュースを格納してみましょう」 [#j989ce95]
NHKのサイトを見ればわかるけど、ニュースをジャンル別にRSSでも配信しているの。もちろんこれには日付データもついてる。
これを取り込んで、新しい順番にソートしたいとしましょうか。
** DBテーブルの作成 [#ta3229ad]
sql = <<SQL
CREATE TABLE nhknews (
yymmdd integer,
date text,
genre text,
desc text,
link text,
title text
);
SQL
名前はNHKニュース、内容は以下の通りね。
,yymmdd,integer,日付を20161102のように整数にして格納。
,date,text,変換前の日付データ
,genre,text,ジャンル(総合ニュースとか社会ニュースとか)
,desc,text,ニュース本文
,link,text,ニュースのURL
,title,text,ニュースタイトル
次に格納処理を書きましょう。RSS処理部は本題じゃないので省略するわね。
** DBテーブルへの登録処理 [#cdfd19d0]
再度呼び出す場合もあるので、一度読みだして更新する処理も含めてあるわ。
みればわかるけど、以下の原則の元に書いてあるわ。
- 同日同時刻にはひとつのデータしかない。
- 一度登録したデータは上書きしない。
あと総数が大した量じゃないので一度全部読み込んでるのよね。これはもちろん、データ数が膨れ上がる種類のデータなら要注意というか、その時は最初から日付指定で読み出しを考えなくちゃならないと思う。
#!/usr/bin/ruby -EUTF-8
require 'rss'
require 'sqlite3'
require 'time'
class Kiji
def initialize(title,link,pubDate,desc,genre)
@title = title.clone
@link = link.clone
@pubDate = pubDate.clone
@yymmdd = nil
begin
if @pubDate.class == String
x2 = @pubDate.gsub(/(年|月)/,'/')
x2.gsub!(/(日|秒)/,'')
x2.gsub!(/(時|分)/,':')
@pubDate = Time.parse(x2)
end
@yymmdd = @pubDate.to_yymmdd
rescue
p @pubDate.class
end
@desc = desc.clone
@genre = genre.clone
end
attr_accessor :title,:link,:pubDate,:yymmdd,:desc,:genre
end
class Time
def to_yymmdd
self.strftime("%Y%m%d%H%M%S").to_i
end
end
class Array2 < Array
def getRss(url)
rss = RSS::Parser.parse(url)
genre = rss.channel.title.gsub(/NHKニュース\|/,'')
if genre =~ /NHK/
genre = "総合"
end
rss.items.each{|item|
n = Kiji.new(item.title, item.link, item.pubDate, item.description, genre)
self.push(n)
}
end
end
Dir.chdir(File.dirname(__FILE__))
db = SQLite3::Database.new("news1.db")
debug = false
debug = true if ARGV.length > 0 && ARGV[0] =- "true"
s = []
begin
# 読み出し
db.execute('select * from nhknews') do |row|
s.push(row)
end
rescue
print "データがなさげなのでテーブル生成:"
sql = <<SQL
CREATE TABLE nhknews (
yymmdd integer,
date text,
genre text,
desc text,
link text,
title text
);
SQL
# テーブル生成
db.execute(sql)
print "OK\n"
end
s2 = []
if s.length > 0
s.each{|d|
if d.class == Array
s2.push(Kiji.new(d[5],d[4],d[1],d[3],d[2]))
end
}
end
# データ書き込みパターン設定
sql = "insert into nhknews values (?, ?, ?, ?, ?, ?)"
ss = Array2.new
ss.getRss("(NHKニュースRSSのあるURL(よそのURLなので直接記載は避けます))")
ss.each{|n|
ff = false
s2.each{|d|
if d.yymmdd == n.yymmdd
ff = true
break
end
}
if ff == true
p "OK!#{n.title}"
else
db.execute(sql, n.yymmdd, n.pubDate.strftime("%Y年%m月%d日 %H時%M分%S秒"), n.genre,n.desc,n.link,n.title)
print <<EOM
[#{n.genre}] #{n.title} (#{n.pubDate}) #{n.yymmdd}
#{n.link}
#{n.desc}
EOM
end
}
** DBデータの読み出し [#k630c694]
さぁ、それじゃ登録したデータを読みこんでみましょうか。
なお「ORDER BY データ名 DESC」は指定データ名による降順ソート(昇順はASC)。うん、便利ねSQL。
k = 30
tday = false
begin
k2 = k - 1
db = SQLite3::Database.new("news1.db")
datas = db.execute("SELECT yymmdd,date,title,desc,link FROM nhknews ORDER BY yymmdd DESC")
s = []
datas.each do |d|
s.push(UNews.new(d[0],d[1],d[2],d[3],d[4]))
end
db.close
s = s[0..k2] if s.length > k
ff = false
s.each{|d|
og = ""
og = "次のニュースです。" if ff == true
date = d.date.clone
if date =~ /#{today}/
date.gsub!(/#{today}/,"本日")
end
next if tday == true && date !~ /本日/ # 今日だけ設定ならそれ以外を飛ばす。
print <<EOM
<dt>#{og}#{date.gsub(/^.+年/,'')} #{d.title}。</dt>
<dd>#{d.desc}</dd>
EOM
ff = true
}
print "\n<dl>\n<p>#{caution}</p>\n#{tail}"
rescue => e
print "DBアクセスでエラーになった。(#{e.message})\n"
exit
end