How to iterate over Postgresql rows in a Python script? - python

I'm writing a script which selects from a DB table and iterates over the rows.
In MySQL I would do:
import MySQLdb
db_mysql=MySQLdb.Connect(user=...,passwd=...,db=..., host=...)
cur = db_mysql.cursor(MySQLdb.cursors.DictCursor)
cur.execute ("""SELECT X,Y,Z FROM tab_a""")
for row in crs.fetchall () :
do things...
But I don't know how to do it in PostgreSQL.
Basically this question could be how to translate the above MySQL code to work with PostgreSQL.
This is what I have so far (I am using PyGreSQL).
import pg
pos = pg.connect(dbname=...,user=...,passwd=...,host=..., port=...)
pos.query("""SELECT X,Y,Z FROM tab_a""")
How do I iterate over the query results?

Retrieved from http://www.pygresql.org/contents/tutorial.html, which you should read.
q = db.query('select * from fruits')
q.getresult()
The result is a Python list of tuples, eardh tuple contains a row, you just need to iterate over the list and iterate or index the tupple.

I think it is the same, you must create cursor, call some fetch and iterate just like in MySQL:
import pgdb
pos = pgdb.connect(database=...,user=...,password=...,host=..., port=...)
sel = "select version() as x, current_timestamp as y, current_user as z"
cursor = db_conn().cursor()
cursor.execute(sel)
columns_descr = cursor.description
rows = cursor.fetchall()
for row in rows:
x, y, z = row
print('variables:')
print('%s\t%s\t%s' % (x, y, z))
print('\nrow:')
print(row)
print('\ncolumns:')
for i in range(len(columns_descr)):
print('-- %s (%s) --' % (columns_descr[i][0], columns_descr[i][1]))
print('%s' % (row[i]))
# this will work with PyGreSQL >= 5.0
print('\n testing named tuples')
print('%s\t%s\t%s' % (row.x, row.y, row.z))

Related

How To Pass Mutiple Values As Parameter In Cursor.Execute Method OF HANA Python Connector

I am using HANA Python Connector's Cursor.execute(sql,hanaparams) method, the parameters to this method are sql statement and hanaparams.My query is like this.
"SELECT * FROM TABLE WHRE COLUMN1 IN(?)" and My PARAMETES ARE VALUE1 ,VALUE2; LIKE LIST/TUPLE;
I am unable to retrieve resultset, Whereas when i run this in HANA with Query and Input Parameters Hard Coded in ,it runs perfectly fine
I am following this tutorial https://developers.sap.com/tutorials/hana-clients-python.html
Any pointers how should i Pass multiple values in Params
Something simple like this seems to work just fine. Count of ? must be equal to count of parameters you have. In your case it takes only VALUE1.
from hdbcli import dbapi
conn = dbapi.connect(
key='HDBKEY'
)
cursor = conn.cursor()
parameters = [11, "2020-12-24"]
params = '?,'*len(parameters)
params2 = params[0:-1]
sql_command2 = f"SELECT {params2} FROM DUMMY;"
cursor.execute(sql_command2, parameters)
rows = cursor.fetchall()
for row in rows:
for col in row:
print ("%s" % col, end=" ")
print (" ")
cursor.close()
conn.close()
So instead of SELECT * FROM TABLE WHERE COLUMN1 IN(?) it should be SELECT * FROM TABLE WHERE COLUMN1 IN(?, ?)

psycopg2 - insert into variable coumns using extras.batch_execution

I am inserting a pandas dataframe into postgres using psycopg2.
Below code:
...
import psycopg2.extras as extras
tuples = [tuple(x) for x in df.to_numpy()]
cols = ','.join(list(column_list))
query = "INSERT INTO %s(%s) VALUES (%%s,%%s,%%s,%%s,%%s)" % (table , cols)
extras.execute_batch(cursor, query, tuples, page_size = 100)
...
This works!
Here, I convert df into tuple, and I think %%s is taking this values at runtime when extras.execute_batch is executed.
The problem is that for this, I need to hardcode %%s, number of times the columns.
In this example its 5 columns, hence I am using %%s,%%s,%%s,%%s,%%s.
Is there a way to have it variable?
Here is what I tried:
...
tuples = [tuple(x) for x in df.to_numpy()]
cols = ','.join(list(column_list))
vals_frame = len(column_list) * """%%s,"""
vals_frame = vals_frame[:-1]
print('vals_frame: ',vals_frame)
query = query = "INSERT INTO %s(%s) VALUES("+vals_frame+")" % (table , cols)
extras.execute_batch(cursor, query, tuples, page_size = 100)
...
This prints:
vals_frame: '%%s,%%s,%%s,%%s,%%s'
which is what I want, but I get below error while creation of query:
TypeError: not all arguments converted during string formatting
How to get past this?
I have tried:
vals_frame = len(column_list) * """\%\%s,"""
vals_frame = len(column_list) * """\\%%s,"""
but this does not seem to work. Can some one help?
The problem is the location of the %. Because of operator precedence, % binds tighter than +. So:
query = "INSERT INTO %s(%s) VALUES("+vals_frame+")" % (table , cols)
The % operator here applies to the string ")". Here are some alternatives to consider:
query = "INSERT INTO %s(%s) VALUES(" % (table, cols) +vals_frame+")"
query = ("INSERT INTO %s(%s) VALUES("+vals_frame+")") % (table , cols)
query = "INSERT INTO %s(%s) VALUES(%s)" % (table, cols, vals_frame)
Alternatively, avoid the problem by using f-strings:
query = f"INSERT INTO {table}({cols}) VALUES({vals_frame});"

Taking variable from mysql record and saving it in python

I couldn't find answer for this so I asked here. I'm making an discord bot in python and I want to get variable in mysql based on two other. serverid and userid. If those 2 variables are found in same record then get third variable in record called level. If no user with combination of serverid and userid is found then set level variable to 1.
This is my code:
mycursor = mydb.cursor()
serveridsql="serverid here"
useridsql="userid here"
val =(serveridsql, useridsql)
sql = "SELECT * FROM users WHERE serverid=%s AND userid=%s"
mycursor.execute(sql, val)
myresult = mycursor.fetchall()
print(...)
I have no idea how to print or save third variable to another because in output I got an table and trying to print "myresult[2]" does not work.
I'm pretty sure you can do a for loop to iterate over the rows in the table you get in myresult:
for row in myresult:
print("userid = ", row[0], )
print("serverid = ", row[1])
Otherwise please show me how your table looks like. You can add dummy data instead of real data before posting.
myresult is a python dataframe. You can try the following-
import numpy as np
myresult['new_level'] = np.where(myresult['serverid'].isnull() & myresult['userid'].isnull(), 1, myresult['level']))
• numpy.where(condition, x, y) - Return elements chosen from x or y depending on condition.
When True, yield x, otherwise yield y.

MYSQL: how to insert statement without specifying col names or question marks?

I have a list of tuples of which i'm inserting into a Table.
Each tuple has 50 values. How do i insert without having to specify the column names and how many ? there is?
col1 is an auto increment column so my insert stmt starts in col2 and ends in col51.
current code:
l = [(1,2,3,.....),(2,4,6,.....),(4,6,7,.....)...]
for tup in l:
cur.execute(
"""insert into TABLENAME(col2,col3,col4.........col50,col51)) VALUES(?,?,?,.............)
""")
want:
insert into TABLENAME(col*) VALUES(*)
MySQL's syntax for INSERT is documented here: http://dev.mysql.com/doc/refman/5.7/en/insert.html
There is no wildcard syntax like you show. The closest thing is to omit the column names:
INSERT INTO MyTable VALUES (...);
But I don't recommend doing that. It works only if you are certain you're going to specify a value for every column in the table (even the auto-increment column), and your values are guaranteed to be in the same order as the columns of the table.
You should learn to use code to build the SQL query based on arrays of values in your application. Here's a Python example the way I do it. Suppose you have a dict of column: value pairs called data_values.
placeholders = ['%s'] * len(data_values)
sql_template = """
INSERT INTO MyTable ({columns}) VALUES ({placeholders})
"""
sql = sql_template.format(
columns=','.join(keys(data_values)),
placeholders=','.join(placeholders)
)
cur = db.cursor()
cur.execute(sql, data_values)
example code to put before your code:
cols = "("
for x in xrange(2, 52):
cols = cols + "col" + str(x) + ","
test = test[:-1]+")"
Inside your loop
for tup in l:
cur.execute(
"""insert into TABLENAME " + cols " VALUES {0}".format(tup)
""")
This is off the top of my head with no error checking

Iterating through python sqlite database

I am trying to iterate through an SQLite database and perform checks or operations on the objects in the list. I need to use a database because the eventual number of objects will be quite large and all the operations are serial in nature (after basic sorting).
My question is how can I iterate through a list and after checking an object for certain qualities put it into a new database object? I would like to perform several serial 'checks' where at most two objects are brought into memory at a time and then re-assigned.
Below is a sample of my code. When I run the last operation I cannot 're-run' the same loop. How can I, instead of just printing the object, save it to a new database?
import os
import sqlite3 as lite
import sys
import random
import gc
import pprint
def make_boxspace():
refine_zone_cube_size = 1
refine_zone_x1 = 1*refine_zone_cube_size
refine_zone_y1 = 1*refine_zone_cube_size
refine_zone_z1 = 1*refine_zone_cube_size
refine_zone_x2 = refine_zone_x1+(2*refine_zone_cube_size)
refine_zone_y2 = refine_zone_y1+(1*refine_zone_cube_size)
refine_zone_z2 = refine_zone_z1+(1*refine_zone_cube_size)
point_pass_length = (1.0/4.0)
outlist = []
for i in range(int((refine_zone_x2-refine_zone_x1)/point_pass_length)):
for j in range(int((refine_zone_y2-refine_zone_y1)/point_pass_length)):
for k in range(int((refine_zone_z2-refine_zone_z1)/point_pass_length)):
if (random.random() > 0.5):
binary = True
else:
binary = False
if binary:
x1 = point_pass_length*i
y1 = point_pass_length*j
z1 = point_pass_length*k
x2 = x1+point_pass_length
y2 = y1+point_pass_length
z2 = z1+point_pass_length
vr_lev = int(random.random()*3)
outlist.append([\
float(str("%.3f" % (x1))),\
float(str("%.3f" % (y1))),\
float(str("%.3f" % (z1))),\
float(str("%.3f" % (x2))),\
float(str("%.3f" % (y2))),\
float(str("%.3f" % (z2))),\
vr_lev
])
return outlist
### make field of "boxes"
boxes = make_boxspace()
### define database object and cursor object
box_data = lite.connect('boxes.db')
cur = box_data.cursor()
### write the list in memory to the database
cur.execute("DROP TABLE IF EXISTS boxes")
cur.execute("CREATE TABLE boxes(x1,y1,z1,x2,y2,z2,vr)")
cur.executemany("INSERT INTO boxes VALUES(?, ?, ?, ?, ?, ?, ?)", boxes)
### clear the 'boxes' list from memory
del boxes
### re-order the boxes
cur.execute("SELECT * FROM boxes ORDER BY z1 ASC")
cur.execute("SELECT * FROM boxes ORDER BY y1 ASC")
cur.execute("SELECT * FROM boxes ORDER BY x1 ASC")
### save the database
box_data.commit()
### print each item
while True:
row = cur.fetchone()
if row == None:
break
print(row)
Thanks guys!!!
I really don't understand what you're asking, but I think you have some fairly fundamental misunderstandings of SQL.
SELECT... ORDER BY does not "order the table", and running commit after a SELECT does not do anything. Sending three separate SELECTs with different ORDER BY but only running fetch once also does not make any sense: you'll only fetch what was provided by the last SELECT.
Perhaps you just want to order by multiple columns at once?
result = cur.execute("SELECT * FROM boxes ORDER BY z1, y1, x1 ASC")
rows = result.fetchall()
I think connecting to the sqlite3 database is as simple as we know that.
since we are accessing database queries and results directly from the database, we need to take all the results in a list with fetchall() method and iterate through that list. so that you can get any number of results in multiple list with single connections.
following is the simple python code
conn = sqlite3.connect("database file name")
cur = conn.cursor()
cur.execute("your query")
a_list = cur.fetchall()
for i in a_list:
"process your list"
"perform another operation using cursor object"

Categories