0

I'm working on a private api that unifies our many dbs/vendor data in one sql db.

We face a challenge with our ESP where our marketers are always changing/adding new columns. We want this app to scale with those column changes and not require massaging columns every time they change names or add new attributes.

I need to create a list of columns on the fly using Rails (we don't want to do this 100% in Mysql, because we're renaming some columns in mapping).

table = "customer"
attrs = ["vendor_cm_name_d", "vendor_cm_email address_d", "vendor_cm_date added_d", "vendor_cm_extid_d" ]

attrs.each_with_index do |attr, i|
  connection = ActiveRecord::Base.connection
  connection.execute( "ALTER TABLE #{table}  ADD COLUMN #{attr} VARCHAR(15);"  )
  # this didnt work :-( connection.close 
end

This approach works a single column but fails with more than one element in the array. reading the logs (pasted below) seems like it's trying to run the entire statement as one call, not transactionally. I tried adding in a connection.close before the end of each loop and that didn't work either. All pointers are welcome.

Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'address_d VARCHAR(15)' at line 1: ALTER TABLE customer  ADD COLUMN vendor_cm_email address_d VARCHAR(15);
ActiveRecord::StatementInvalid: Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'address_d VARCHAR(15)' at line 1: ALTER TABLE customer  ADD COLUMN vendor_cm_email address_d VARCHAR(15);
7
  • 1
    This is probably a super bad idea. Why not pivot to a schemaless type design? MySQL 5.7 supports JSON columns which are great for this sort of thing, though the down-side is they can't be easily indexed or manipulated. Postgres provides excellent support for JSON, you can index it and manipulate it quite easily, which might be worth considering as an option. There's also more pure document stores like MongoDB that go all-in on this concept. Commented Aug 1, 2017 at 22:15
  • Another more pure RDBMS approach is to create a key/value table pair for your row data. This can get extremely messy and is often held up as an anti-pattern, but it can get you out of a jam like this where you really don't know what data you need to accommodate. Altering large tables can bring your server to its knees and can cause severe service disruptions at scale. It's something you want to do reluctantly, not by design. Commented Aug 1, 2017 at 22:16
  • @tadman yeah I agree. I;d never do this anywhere else but a private api for our data warehouse. Commented Aug 1, 2017 at 22:20
  • If you're doing it specifically for warehousing, the Star Schema can simplify implementation. Commented Aug 1, 2017 at 22:20
  • Sorry that submitted early @tadman. Upgrading sql version or using serialized columns is deal breaker. We have too much investment in SQL that;s not worth getting into here, and we need to be able to query by sql on a col by col basis. Fully understand your points/approach tho, appreciate the notes so far! Commented Aug 1, 2017 at 22:23

1 Answer 1

2

Your sql doesn't work because column names have space. Wrap you column names in generated sql with quotes.

attrs.each_with_index do |x, i|
  connection = ActiveRecord::Base.connection
  connection.execute "ALTER TABLE #{table}  ADD COLUMN \"#{x}\" VARCHAR(15);" 
# this didnt work :-( connection.close 
end

Though I would rather not go down the path of writing sql myself. Instead you can create a service like this:

class DbService < ActiveRecord::Migration
  def initialize(table_name)
    @table_name = table_name
  end
  def add_string_column(column_name)
    add_column @table_name, column_name, :string
  end
end

And then do something like

service = DbService.new("customer")
attrs.each do |column_name|
  service.add_string_column(column_name)
end
Sign up to request clarification or add additional context in comments.

1 Comment

I cannot believe I missed that. I used a rails helper to replace spaces with underscores, that clearly had an issue. Resolved. Thanks so much!!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.