![](/img/trans.png)
[英]How should I import data into QuickBooks from my Rails application?
[英]How should I import this data into my database?
我有成千上萬條記錄的數據庫
Code | Name | Price
00106 | Water | 9.99
00107 | Onion | 8.99
編碼在GES
文件中,如下所示:
00F
表示列標題 00I
表示插入一行 還有其他類似的東西( 00D
代表刪除行或00U
代表更新行)
00F
0101
02Code
031
00F
0102
02Name
031
00F
0103
02Price
030
00I
0100106
02Water
030999
00I
0100107
02Onion
030899
我想創建處理該文件並將其推入數據庫的導入程序。 所以我開始實現:
class Importer
CONN = ActiveRecord::Base.connection
F = "00F"
I = "00I"
def extract_to_database(collection)
add = true
tmp = []
type = F
inserts = []
collection.each_with_index do |line, i|
_type = line.strip
_changed = [F,I].include? _type
if _changed && i > 0
case type
when F then @f << tmp
when I
group_id = Group.find_by(code: tmp[1]).id
inserts.push "(group_id,'#{tmp[2]}','#{tmp[3]}')"
end
tmp = []
type = _type
end
tmp << line
end
sql = "INSERT INTO products (`group_id`, `name`, `price`) VALUES #{inserts.join(", ")}"
CONN.execute sql
end
end
這樣做有一個問題,我想使用函數式編程來重構它。
而且我將不得不通過code
找到其他模型,並將其放入與some_model_id
列相關的products
表中,這樣會使整個過程變得復雜。 因為現在導入此數據需要我幾個小時。
也許使用Ruby並不是最佳選擇。
Ruby沒有什么無法處理的。 尚不清楚“函數式編程”將如何幫助解決這一問題,因為這是經典的狀態機問題,正在進行一些簡單的數據轉換。
腳手架示例:
class SomethingImporter
FIELD_MARKER = "00F"
INSERT_MARKER = "00I"
COLUMNS = %w[ group_id name price ]
# Performs the insert into a given model. This should probably be a class
# method on the model itself.
def bulk_insert(model, rows)
sql = [
"INSERT INTO `#{model.table_name}` (#{columns.collect { |c| }}"
]
# Append the placeholders: (?,?,?),(?,?,?),...
sql[0] += ([ '(%s)' % ([ '?' ] * COLUMNS.length).join(',') ] * rows.length).join(',')
sql += rows.flatten
model.connection.execute(model.send(:sanitize_sql, sql))
end
# Resolve a group code to a group_id value, and cache the result so that
# subsequent look-ups for the same code are valid.
def group_id(group_code)
@find_group ||= { }
# This tests if any value has been cached for this code, including one
# that might be nil.
if (@find_group.key?(group_code))
return @find_group[group_code]
end
group = Group.find_by(code: group_code)
@find_group[group_code] = group && group.id
end
# Call this with the actual collection, lines stripped, and with any header
# lines removed (e.g. collection.shift)
def extract_rows(collection)
state = nil
rows = [ ]
row = [ ]
collection.each_with_index do |line|
case (line)
when FIELD_MARKER
# Indicates field data to follow
state = :field
when INSERT_MARKER
case (state)
when :insert
rows << [ row[0], row[1], (row[2].sub(/^0+/, '').to_f / 100) ]
end
state = :insert
row = [ ]
else
case (state)
when :field
# Presumably you'd pay attention to the data here and establish
# a mapping table.
when :insert
row << line.sub(/^\d\d/, '')
# puts row.inspect
end
end
end
case (state)
when :insert
rows << [ row[0], row[1], (row[2].sub(/^0+/, '').to_f / 100) ]
end
rows
end
end
data = <<END
00F
0101
02Code
031
00F
0102
02Name
031
00F
0103
02Price
030
00I
0100106
02Water
030999
00I
0100107
02Onion
030899
END
importer = SomethingImporter.new
puts importer.extract_rows(data.split(/\n/)).inspect
根據您的數據,此示例輸出如下所示:
[["00106", "Water", 9.99], ["00107", "Onion", 8.99]]
在編寫這樣的代碼時,請確保公開中間結果 ,以便能夠測試正在發生的事情。 您的實現只需一次就可以獲取數據並將其直接轉儲到數據庫中,這使得很難判斷出問題出在哪里,如果不能正確解決。 此版本由幾種方法組成,每種方法都有更特定的用途。
在原始示例中尚不清楚為什么要解析group_id
,示例輸出與此無關,但是作為示例,我包含了一種解析它們並保留其緩存的方法,避免了重復查找相同的結果事情。 對於較大規模的導入,您可能會加載許多行,提取出不同的group_id值,一次加載所有這些值,然后在插入之前重新映射它們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.