[[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

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS