Ruby DBI 提取无法处理 MySQL 中的全零日期
Ruby DBI fetch can't handle all-zero dates in MySQL
我正在尝试使用一些相当简单的 CGI/Ruby 和 DBI 来访问我们的数据库:
#!/usr/bin/ruby -w
require "dbi"
dbh = DBI.connect("dbi:Mysql:my:mydb", "XXXX", "XXXX")
...
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch() do
# Do some stuff
...
end
大部分时间都可以正常工作,但我打破了记录并出现错误:
/usr/lib/ruby/vendor_ruby/dbd/Mysql.rb:120:in `parse': invalid date (ArgumentError)
from /usr/lib/ruby/vendor_ruby/dbd/Mysql.rb:120:in `parse'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:66:in `block in convert_types'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `each'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `each_with_index'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `convert_types'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:75:in `set_values'
from /usr/lib/ruby/vendor_ruby/dbi/handles/statement.rb:226:in `fetch'
from /usr/lib/cgi-bin/test:39:in `block in <main>'
from /usr/lib/cgi-bin/test:36:in `each'
from /usr/lib/cgi-bin/test:36:in `<main>'
经过一些侦探工作后,我发现它的日期为 0000-00-00,fetch()
不喜欢。未定义的日期是可以的,Perl 中的 DBI 可以处理所有零日期,只是 Ruby.
中的 DBI
我可以修复数据库,我会尝试让将值写入数据库的应用程序也修复,但我认为我的 Ruby 应该对这些事情有弹性。有没有办法解决这个问题,也许使用 rescue
以某种方式?
这是我想出的解决方案:
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
begin
while row = rows.fetch() do
# Do some stuff
...
end
rescue Exception => e
puts "#{e}<br>\n"
retry
end
这工作得很好,就好像重试开始一个新的 while 循环一样,行保持其状态,因此提取在下一条记录上恢复。
唯一的问题是很难识别不良记录。为了解决这个问题,我在没有违规字段的情况下发出了更多查询。我有点难看的解决方案:
results = Hash.new
hit_error = false
query = "select ETA,UNIQUE_ID from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
begin
while row = rows.fetch() do
# Do some stuff
...
results[row[1]] = row[0]
end
rescue Exception => e
hit_error = true
retry
end
if hit_error
query = "select UNIQUE_ID from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch() do
id = row[0]
unless results.has_key?(id)
begin
query = "select ETA for mydb.mytable where UNIQUE_ID = #{id} limit 1"
error = dbh.execute(query)
error.fetch() # expect this to hit same error as before
puts "Unexpected success for UNIQUE_ID #{id}<br>\n"
rescue Exception => e
puts "#{e} at UNIQUE_ID #{id}<br>\n"
end
end
end
end
最后我不确定使用 DBI/Ruby 的有效性如何,它似乎已被弃用。 MySQL/Ruby 也一样。我也试过 Sequel 但收效甚微。
另一种解决方案是使用 fetch_hash
。这会将所有数据作为字符串获取,这有点尴尬,因为您需要转换为日期、整数等,但确实让您有机会在显式转换中捕获错误。这也使得识别不良记录变得更加容易:
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch_hash() do
begin
eta = Date.parse row["ETA"]
# Do something with the ETA
...
rescue Exception => e
puts "Error parsing date '#{row["ETA"]}': #{e}<br>\n"
# Make do without the ETA
...
end
end
如果使用 mysql 适配器,Sequel 可以处理无效日期:
DB = Sequel.connect('mysql://user:password@host/database')
DB.convert_invalid_date_time = :string # or nil
DB.get(Sequel.cast('0000-00-00', Date))
# => "0000-00-00"
我正在尝试使用一些相当简单的 CGI/Ruby 和 DBI 来访问我们的数据库:
#!/usr/bin/ruby -w
require "dbi"
dbh = DBI.connect("dbi:Mysql:my:mydb", "XXXX", "XXXX")
...
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch() do
# Do some stuff
...
end
大部分时间都可以正常工作,但我打破了记录并出现错误:
/usr/lib/ruby/vendor_ruby/dbd/Mysql.rb:120:in `parse': invalid date (ArgumentError)
from /usr/lib/ruby/vendor_ruby/dbd/Mysql.rb:120:in `parse'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:66:in `block in convert_types'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `each'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `each_with_index'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:65:in `convert_types'
from /usr/lib/ruby/vendor_ruby/dbi/row.rb:75:in `set_values'
from /usr/lib/ruby/vendor_ruby/dbi/handles/statement.rb:226:in `fetch'
from /usr/lib/cgi-bin/test:39:in `block in <main>'
from /usr/lib/cgi-bin/test:36:in `each'
from /usr/lib/cgi-bin/test:36:in `<main>'
经过一些侦探工作后,我发现它的日期为 0000-00-00,fetch()
不喜欢。未定义的日期是可以的,Perl 中的 DBI 可以处理所有零日期,只是 Ruby.
我可以修复数据库,我会尝试让将值写入数据库的应用程序也修复,但我认为我的 Ruby 应该对这些事情有弹性。有没有办法解决这个问题,也许使用 rescue
以某种方式?
这是我想出的解决方案:
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
begin
while row = rows.fetch() do
# Do some stuff
...
end
rescue Exception => e
puts "#{e}<br>\n"
retry
end
这工作得很好,就好像重试开始一个新的 while 循环一样,行保持其状态,因此提取在下一条记录上恢复。
唯一的问题是很难识别不良记录。为了解决这个问题,我在没有违规字段的情况下发出了更多查询。我有点难看的解决方案:
results = Hash.new
hit_error = false
query = "select ETA,UNIQUE_ID from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
begin
while row = rows.fetch() do
# Do some stuff
...
results[row[1]] = row[0]
end
rescue Exception => e
hit_error = true
retry
end
if hit_error
query = "select UNIQUE_ID from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch() do
id = row[0]
unless results.has_key?(id)
begin
query = "select ETA for mydb.mytable where UNIQUE_ID = #{id} limit 1"
error = dbh.execute(query)
error.fetch() # expect this to hit same error as before
puts "Unexpected success for UNIQUE_ID #{id}<br>\n"
rescue Exception => e
puts "#{e} at UNIQUE_ID #{id}<br>\n"
end
end
end
end
最后我不确定使用 DBI/Ruby 的有效性如何,它似乎已被弃用。 MySQL/Ruby 也一样。我也试过 Sequel 但收效甚微。
另一种解决方案是使用 fetch_hash
。这会将所有数据作为字符串获取,这有点尴尬,因为您需要转换为日期、整数等,但确实让您有机会在显式转换中捕获错误。这也使得识别不良记录变得更加容易:
query = "select ETA from mydb.mytable where ID = #{someval}"
rows = dbh.execute(query)
while row = rows.fetch_hash() do
begin
eta = Date.parse row["ETA"]
# Do something with the ETA
...
rescue Exception => e
puts "Error parsing date '#{row["ETA"]}': #{e}<br>\n"
# Make do without the ETA
...
end
end
Sequel 可以处理无效日期:
DB = Sequel.connect('mysql://user:password@host/database')
DB.convert_invalid_date_time = :string # or nil
DB.get(Sequel.cast('0000-00-00', Date))
# => "0000-00-00"