how to insert values into mysql table from another bigquery response - mysql

My Python program connects to BigQuery and fetching data which I want to insert into a MySQL table. It's successfully fetching the results from BigQuery. It's also successfully connecting to MySQL DB but it's not inserting the data. I see its complaining for the row[1].
What's the right way to insert the values from BigQuery response into MySQL table columns?
query_data = {mybigquery}
query_response = query_request.query(projectId='myprojectid',body=query_data).execute()
for row in query_response['rows']:
cursor.execute ("INSERT INTO database.table VALUES ('row[0]','row[1]','row[2]','row[3]','row[4]');")
Also, I tried to use
cursor.execute ("INSERT INTO database.table VALUES (%s,%s,%s,%s,%s);")
or
cursor.execute ("INSERT INTO database.table VALUES (row[0],row[1],row[2],row[3],row[4]);")
But in all it fails while inserting values in mysql table

String literals
Regarding the original question, the issue lies with quoting your variables. This causes the execute function to treat them as string literals rather than getting the values from them.
As suggested by #Herman, to properly execute the SQL statement with the values I think you intend, you would need something more like this:
query_data = {mybigquery}
statement = 'INSERT INTO database.table VALUE (%s, %s, %s);'
response = query_request.query(projectId='myprojectid', body=query_data).execute()
rows = response['rows']
for row in rows:
values = (row[0], row[1], row[2])
cursor.execute(statement, values)
BigQuery query JSON
Keep in mind however that the above will not work out of the box as row in the code above does not conform to the response received from the BigQuery Job: query API.
In this API, rows is an array of row objects. Each row object has a property f which is an array of fields. Lastly, each field has a property v which is the value of this field.
To get the value of second field in a row, you should use row['f'][1]['v']. Since you require a tuple or list for the params argument of the cursor.execute() method, you could get a list of field values using list comprehension as follows:
for row in rows:
values = [field['v'] for field in row['f]]
Sanitize values before inserting
The TypeError you get once correctly reading the field values may be raised because execute or str cannot convert a value to a string properly. One of the significant differences between BigQuery and MySQL is that a value in BigQuery can be a record with multiple values of its own. To ensure this gets inserted properly, you must sanitize those values yourself prior to inserting them. If the value is a list or dict, it cannot be stored in MySQL without being serialized in some way like with the str method.
Example
def sanitize(value):
if type(value) is list:
return str(value)
if type(value) is dict:
return str(value)
# this may be required for other types
return value
data = {mybigquery}
statement = 'INSERT INTO database.table VALUE (%s, %s, %s);'
response = request.query(projectId='projid', body=data).execute()
for row in response['rows']:
values = [sanitize(field['v']) for field in row['f']]
cursor.execute(statement, values)
This is very basic sanitation. You should really validate all field values and ensure that they will be properly converted to MySQL types and not simply insert an array of values.

What is the error message? It should be something like:
cursor.execute(
"INSERT INTO database.table VALUES (%s, %s, %s, %s, %s)", row[0:5])

Related

Is this Syntax correct for python insert operation for mysql? I got error - TypeError: 'str' object is not callable?

cmd="insert into People(ID,Name,Age,Gender,CriminalRecords)values("+str(Id)+","+str(Name)+","+str(Age)+","+str(Gender)+","+str(Criminal)+")"
The values that are strings need quotes around them.
But it's better to use a query with parameters rather than concatenating variables.
cmd="insert into People(ID,Name,Age,Gender,CriminalRecords)values(%s, %s, %s, %s, %s)"
cursor.execute(cmd, (Id, Name, Age, Gender, Criminal))
conn.commit()
Replace cursor and conn with the actual variables containing your cursor and connection objects.

Error inserting multiple data formats in a database with my sql using a loop

I'm really new in this programming world, I'm working on a project where I need to extract some values from an API and insert them into a SQL base , also I need to figure out how to only add values beyond the last date in the database, right now I have this block of code and I'm getting this error message
def datodolar():
pagina = urlopen("https://apis.datos.gob.ar/series/api/series/?ids=168.1_T_CAMBIOR_D_0_0_26&start_date=2018-07&limit=5000")
json_str = pagina.read().decode("utf8")
return json.loads(json_str)
historicodolar=datodolar()
valoresdolar = historicodolar["data"]
#for values in valoresdolar:
#print(values[1])
dateforuse= datetime.now()
for values in valoresdolar:
objStr = datetime.strftime(dateforuse, '%Y-%m-%d')
objStr3 = datetime.strptime(values[0], '%Y-%m-%d')
objStr2 = datetime.strftime(objStr3, '%Y-%m-%d')
#print(fecha, " ----> ", objDate," ----> ",objStr)
sql =("INSERT INTO dolar (fechadato,tipo_cambio,fechacarga) VALUES (%s, %s,%s)", (objStr2, values[1],objStr))
#"insert into dolar(fechadato,tipo_cambio,fechacarga) values ('"+(objStr3)+"','"(values)[1]+"','"+(objStr)+"')"
#print(sql)
cursor.execute(sql)
conexion.commit()
The error message is
sql ="insert into dolar(fechadato,tipo_cambio,fechacarga) values ('"+str(objStr3)+"','"(values)[1]+"','"+str(objStr)+"')"
TypeError: 'str' object is not callable
I tried a couple of different ways to insert the values in the database but with both get different error messages.
Thanks so much for any hint about how to solve this.

When creating a namedtuple, how do I substitute a value?

I'm pulling data from the NHTSA API, using a JSON format. I'm then creating a named tuple from this data and a few other sources and using this as a record to insert into a MySQL database.
The NHTSA API uses '' to designate a null value which is not an accepted value in for this particular column in database. The column only allows a float datatype.
When creating my named tuple, is there a way to substitute None if a specific value is returned? I.e. if API call returns '', use None instead?
Error returned is
Failed inserting object into MySQL table Error while executing statement: Data truncated for column 'weight' at row 1
Tuples are immutable, hence you need to create a new tuple
Here's an example:
old = (1,2,'ABC','','','','text')
new = tuple(None if x == '' else x for x in old)
Output:
Now new contains:
(1, 2, 'ABC', None, None, None, 'text')
Refer this thread for more information
To replace one specific field value in namedtuple / NamedTuple in an easier way you can use _replace() method.
Point = namedtuple('Point', 'x,y')
p = Point(x=11, y=22)
p = p._replace(x=33)
print(p)
It will print:
Point(x=33, y=22)
_replace() substitutes a field specified with keyword argument with its value, and returns a new namedtuple with that value and the rest of values copied from an old namedtuple.

Python Mysqldb insert error

I'm using MySQLdb and Python to insert data into the local database.
The insert query is
for row in v1:
cur2.execute("""""INSERT INTO s_test (CO1,CO2, CO3, CO4, CO5) VALUES (%s, %s, %s, %s, %s);""""",(row[0],row[1], row[2],row[3], row[4]));
I get the error
IndexError: tuple index out of range
If I use the query below, I get no errors
for row in v1:
cur2.execute("INSERT INTO s_test (CO1) VALUES (%s);",(row[0]));
If I increase the number of columns into which I insert, I get the same error mentioned above.
What is the correct syntax?
I don't remember much about Python, but this sounds like you don't have 5 elements in the row array, more than a SQL error. Can you check that?
Assuming the data's entirely numerical, you could try this:
cur2.execute("""INSERT INTO s_test (CO1, CO2, CO3, CO4, CO5) VALUES ({0}, {1}, {2}, {3}, {4});""".format(row[0], row[1], row[2], row[3], row[4]);
Use 3 quotes instead of 5; replace the comma with a period; use the more modern .format string substitution.

MySQL Dynamic Query Statement in Python with Dictionary

Very similar to this question MySQL Dynamic Query Statement in Python
However what I am looking to do instead of two lists is to use a dictionary
Let's say i have this dictionary
instance_insert = {
# sql column variable value
'instance_id' : 'instnace.id',
'customer_id' : 'customer.id',
'os' : 'instance.platform',
}
And I want to populate a mysql database with an insert statement using sql column as the sql column name and the variable name as the variable that will hold the value that is to be inserted into the mysql table.
Kind of lost because I don't understand exactly what this statement does, but was pulled from the question that I posted where he was using two lists to do what he wanted.
sql = "INSERT INTO instance_info_test VALUES (%s);" % ', '.join('?' for _ in instance_insert)
cur.execute (sql, instance_insert)
Also I would like it to be dynamic in the sense that I can add/remove columns to the dictionary
Before you post, you might want to try searching for something more specific to your question. For instance, when I Googled "python mysqldb insert dictionary", I found a good answer on the first page, at http://mail.python.org/pipermail/tutor/2010-December/080701.html. Relevant part:
Here's what I came up with when I tried to make a generalized version
of the above:
def add_row(cursor, tablename, rowdict):
# XXX tablename not sanitized
# XXX test for allowed keys is case-sensitive
# filter out keys that are not column names
cursor.execute("describe %s" % tablename)
allowed_keys = set(row[0] for row in cursor.fetchall())
keys = allowed_keys.intersection(rowdict)
if len(rowdict) > len(keys):
unknown_keys = set(rowdict) - allowed_keys
print >> sys.stderr, "skipping keys:", ", ".join(unknown_keys)
columns = ", ".join(keys)
values_template = ", ".join(["%s"] * len(keys))
sql = "insert into %s (%s) values (%s)" % (
tablename, columns, values_template)
values = tuple(rowdict[key] for key in keys)
cursor.execute(sql, values)
filename = ...
tablename = ...
db = MySQLdb.connect(...)
cursor = db.cursor()
with open(filename) as instream:
row = json.load(instream)
add_row(cursor, tablename, row)
Peter
If you know your inputs will always be valid (table name is valid, columns are present in the table), and you're not importing from a JSON file as the example is, you can simplify this function. But it'll accomplish what you want to accomplish. While it may initially seem like DictCursor would be helpful, it looks like DictCursor is useful for returning a dictionary of values, but it can't execute from a dict.