簡體   English   中英

我應該如何將這些數據導入數據庫?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM