How would I setup a stored procedure in MySQL to use external variables.
I have written SP before, but not with extenal inputs. With connection string coming from pyODBC.
Then, using python how would I call that Sp and input that variable?
cursor.execute('Call d.MySP' ????)
Assuming you are using MySQLdb, according to the docs, the call would be:
cursor.callproc('d.MySP',args)
A peek under the hood shows how the variables are set and the CALL statement is made:
def callproc(self, procname, args=()):
from types import UnicodeType
db = self._get_db()
charset = db.character_set_name()
for index, arg in enumerate(args):
q = "SET #_%s_%d=%s" % (procname, index,
db.literal(arg))
if isinstance(q, unicode):
q = q.encode(charset)
self._query(q)
self.nextset()
q = "CALL %s(%s)" % (procname,
','.join(['#_%s_%d' % (procname, i)
for i in range(len(args))]))
if type(q) is UnicodeType:
q = q.encode(charset)
self._query(q)
self._executed = q
if not self._defer_warnings: self._warning_check()
return args
Related
We are trying to migrate our app from cx oracle into session pool session, but seems there is a difference in the return pool for the execute query.
The cx oracle version is 7.2.1
Is there a way to convert the result into a list of Records or List of Set/Dict?
Using Normal Session, the return is list of Record.
Using Session Pool, the return is list of tuple.
Here is the code for the query in normal session
def execute_query(self, sql_query, parameters=None):
if parameters is None:
self.cursor.execute(sql_query)
else:
self.cursor.execute(sql_query, parameters)
result = self.cursor.fetchall()
return result
Here is the code for the query in session pool
def execute_query(self, sql_query, parameters=None):
if parameters is None:
self.cursor.execute(sql_query)
self.cursor.rowfactory = lambda *args: dict(zip([d[0].lower() for d in self.cursor.description], args))
else:
self.cursor.execute(sql_query, parameters)
self.cursor.rowfactory = lambda *args: dict(zip([d[0].lower() for d in self.cursor.description], args))
result = self.cursor.fetchall()
return result
Thanks for your help.
Well, my solution is using sqlalchemy and cx_Oracle,
use sqlalchemy create connect session and execute sql cmd:
result = self.session.execute(sql_cmd)
return [{k: v for k, v in row.items()} for row in result]
I have some code that successfully creates a new node using the Python Bolt Neo4j driver. However, I cannot create new relationships in the same transaction.
I am using Python 2.7 with the Neo4j Bolt drive 1.7.2.
with conn.session() as session:
uuid = getNewUUID()
tx = None
try:
tx = session.begin_transaction()
stmt = "CREATE (a:{type} {{{uuid_attrib}: $uuid, {name_attrib}: $name, {desc_attrib}: $desc, {has_phi_attrib}: $has_phi}}) RETURN a.{uuid_attrib}".format(
type=ENTITY_NODE_NAME, uuid_attrib=UUID_ATTRIBUTE,
name_attrib=NAME_ATTRIBUTE, desc_attrib=DESCRIPTION_ATTRIBUTE,
has_phi_attrib=HAS_PHI_ATTRIBUTE)
#print "EXECUTING: " + stmt
tx.run(stmt, uuid=uuid, name=name, desc=description, has_phi=hasPHI)
create_relationship(tx, uuid, DERIVED_FROM_REL, parentUUID)
create_relationship(tx, uuid, LAB_CREATED_AT_REL, labCreatedUUID)
create_relationship(tx, uuid, CREATED_BY_REL, createdByUUID)
tx.commit()
return uuid
here is the create_relationship method:
def create_relationship(tx, startuuid, rel_label, enduuid):
try:
stmt = "MATCH (a),(b) WHERE a.uuid = '$startuuid' AND b.uuid = '$enduuid' CREATE (a)-[r:{rel_label}]->(b) RETURN type(r)".format(
rel_label=rel_label)
temp_stmt = stmt
temp_stmt = temp_stmt.replace("$startuuid", startuuid)
temp_stmt = temp_stmt.replace("$enduuid", enduuid)
print "EXECUTING: " + temp_stmt
result = tx.run(stmt,startuuid=startuuid, enduuid=enduuid)
The code successfully creates the node in Neo4j. However, the relationships are never created. I expected the relationships to be added to the node. If I copy and paste the relationship CREATE commands into the bolt web interface, the CREATE command works.
I am not sure if this is the exact issue but it looks like transaction tx is passed as value and create_relationship function creates its own local copy of tx so original tx is not modified by the function create_relationship.
When you commit the tx, transactions from create_relationship function are not committed as these are not part of the tx.
You should consider running these transactions in the calling function itself instead of create_relationship, use create_relationship or similar function to create and return the statement and run these statement in the calling function.
Function to get statement:
def get_relationship_statement(startuuid, rel_label, enduuid):
stmt = "MATCH (a),(b) WHERE a.uuid = '$startuuid' AND b.uuid = '$enduuid' CREATE (a)-[r:{rel_label}]->(b) RETURN type(r)".format(
rel_label=rel_label)
temp_stmt = stmt
temp_stmt = temp_stmt.replace("$startuuid", startuuid)
temp_stmt = temp_stmt.replace("$enduuid", enduuid)
print "Statement: " + temp_stmt
return stmt
Replace
create_relationship(tx, uuid, DERIVED_FROM_REL, parentUUID)
with
tx.run(get_relationship_statement(uuid, DERIVED_FROM_REL, parentUUID),startuuid=uuid, enduuid=parentUUID)
I have a script that calls a list of linux guests I am trying to tidy up. Here is the code:
#!/usr/bin/python
guests = ['guest1','guest2','guest3','guest*']
def serverCheck(guestList)
for g in guestList:
server = AdminControl.completeObjectName('cell=tstenvironment,node=guest1,name=uatenvironment,type=Server,*')
try:
status = AdminControl.getAttribute(server, 'state')
print g + status
except:
print "Error %s is down." % g
serverCheck(guests)
The problem lies in this line:
server = AdminControl.completeObjectName('cell=Afcutst,node=%s,name=afcuuat1,type=Server,*') % g
How do I use my list to populate the node variable while still being able to pass the info within the parentheses to the AdminControl function?
The argument string itself is the argument to the % operator, not the return value of the function call.
server = AdminControl.completeObjectName(
'cell=Afcutst,node=%s,name=afcuuat1,type=Server,*' % (g,)
)
Peeking into the crystal ball, Python 3.6 will allow you to write
server = AdminControl.completeObjectName(
f'cell=Afcutst,node={g},name=afcuuat1,type=Server,*'
)
embedding the variable directly into a special format string literal.
can you try like this
AdminControl.completeObjectName('cell=tstenvironment,node=%s,name=uatenvironment,type=Server,*'%g)
For more readability I would suggest this and also using the same way to format strings from variables (here I chose str.format)
guests = ['guest1','guest2','guest3','guest*']
def serverCheck(guestList)
name_tpl = 'cell=tstenvironment,node={},name=uatenvironment,type=Server,*'
for g in guestList:
obj_name = name_tpl.format(g)
server = AdminControl.completeObjectName(obj_name)
try:
status = AdminControl.getAttribute(server, 'state')
print '{}: {}'.format(g, status)
except:
print 'Error {} is down'.format(g)
serverCheck(guests)
By default, cx_Oracle returns each row as a tuple.
>>> import cx_Oracle
>>> conn=cx_Oracle.connect('scott/tiger')
>>> curs=conn.cursor()
>>> curs.execute("select * from foo");
>>> curs.fetchone()
(33, 'blue')
How can I return each row as a dictionary?
You can override the cursor's rowfactory method. You will need to do this each time you perform the query.
Here's the results of the standard query, a tuple.
curs.execute('select * from foo')
curs.fetchone()
(33, 'blue')
Returning a named tuple:
def makeNamedTupleFactory(cursor):
columnNames = [d[0].lower() for d in cursor.description]
import collections
Row = collections.namedtuple('Row', columnNames)
return Row
curs.rowfactory = makeNamedTupleFactory(curs)
curs.fetchone()
Row(x=33, y='blue')
Returning a dictionary:
def makeDictFactory(cursor):
columnNames = [d[0] for d in cursor.description]
def createRow(*args):
return dict(zip(columnNames, args))
return createRow
curs.rowfactory = makeDictFactory(curs)
curs.fetchone()
{'Y': 'brown', 'X': 1}
Credit to Amaury Forgeot d'Arc:
http://sourceforge.net/p/cx-oracle/mailman/message/27145597
A very short version:
curs.rowfactory = lambda *args: dict(zip([d[0] for d in curs.description], args))
Tested on Python 3.7.0 & cx_Oracle 7.1.2
Old question but adding some helpful links with a Python recipe
According to cx_Oracle documentation:
Cursor.rowfactory
This read-write attribute specifies a method to call for each row that
is retrieved from the database. Ordinarily a tuple is returned for
each row but if this attribute is set, the method is called with the
tuple that would normally be returned, and the result of the method is
returned instead.
The cx_Oracle - Python Interface for Oracle Database Also points to GitHub repository for lots of helpful sample examples. Please check GenericRowFactory.py.
Googled: This PPT can be further helpful: [PDF]CON6543 Python and Oracle Database - RainFocus
Recipe
Django database backend for Oracle under the hood uses cx_Oracle. In earlier versions ( Django 1.11- ) they have written _rowfactory(cursor, row) That also cast cx_Oracle's numeric data types into relevant Python data and strings into unicode.
If you have installed Django Please check base.py as follows:
$ DJANGO_DIR="$(python -c 'import django, os; print(os.path.dirname(django.__file__))')"
$ vim $DJANGO_DIR/db/backends/oracle/base.py
One can borrow _rowfactory() from $DJANGO_DIR/db/backends/oracle/base.py and can apply below decorator naming to make it return namedtuple instead of simple tuple.
mybase.py
import functools
from itertools import izip, imap
from operator import itemgetter
from collections import namedtuple
import cx_Oracle as Database
import decimal
def naming(rename=False, case=None):
def decorator(rowfactory):
#functools.wraps(rowfactory)
def decorated_rowfactory(cursor, row, typename="GenericRow"):
field_names = imap(case, imap(itemgetter(0), cursor.description))
return namedtuple(typename, field_names)._make(rowfactory(cursor, row))
return decorated_rowfactory
return decorator
use it as:
#naming(rename=False, case=str.lower)
def rowfactory(cursor, row):
casted = []
....
....
return tuple(casted)
oracle.py
import cx_Oracle as Database
from cx_Oracle import *
import mybase
class Cursor(Database.Cursor):
def execute(self, statement, args=None):
prepareNested = (statement is not None and self.statement != statement)
result = super(self.__class__, self).execute(statement, args or [])
if prepareNested:
if self.description:
self.rowfactory = lambda *row: mybase.rowfactory(self, row)
return result
def close(self):
try:
super(self.__class__, self).close()
except Database.InterfaceError:
"already closed"
class Connection(Database.Connection):
def cursor(self):
Cursor(self)
connect = Connection
Now, instead of import cx_oracle import oracle in user script as:
user.py
import oracle
dsn = oracle.makedsn('HOSTNAME', 1521, service_name='dev_server')
db = connect('username', 'password', dsn)
cursor = db.cursor()
cursor.execute("""
SELECT 'Grijesh' as FirstName,
'Chauhan' as LastName,
CAST('10560.254' AS NUMBER(10, 2)) as Salary
FROM DUAL
""")
row = cursor.fetchone()
print ("First Name is %s" % row.firstname) # => Grijesh
print ("Last Name is %s" % row.lastname) # => Chauhan
print ("Salary is %r" % row.salary) # => Decimal('10560.25')
Give it a Try!!
Building up on answer by #maelcum73 :
curs.rowfactory = lambda *args: dict(zip([d[0] for d in curs.description], args))
The issue with this solution is that you need to re-set this after every execution.
Going one step further, you can create a shell around the cursor object like so:
class dictcur(object):
# need to monkeypatch the built-in execute function to always return a dict
def __init__(self, cursor):
self._original_cursor = cursor
def execute(self, *args, **kwargs):
# rowfactory needs to be set AFTER EACH execution!
self._original_cursor.execute(*args, **kwargs)
self._original_cursor.rowfactory = lambda *a: dict(
zip([d[0] for d in self._original_cursor.description], a)
)
# cx_Oracle's cursor's execute method returns a cursor object
# -> return the correct cursor in the monkeypatched version as well!
return self._original_cursor
def __getattr__(self, attr):
# anything other than the execute method: just go straight to the cursor
return getattr(self._original_cursor, attr)
dict_cursor = dictcur(cursor=conn.cursor())
Using this dict_cursor, every subsequent dict_cursor.execute() call will return a dictionary. Note: I tried monkeypatching the execute method directly, however that was not possible because it is a built-in method.
I am attempting to figure out how to use the IN keyword in a django model query.
I was attempting to replace:
db = database.connect()
c = db.cursor()
c.execute("SELECT MAX(Date) FROM `Requests` WHERE UserId = %%s AND VIN = %%s AND Success = 1 AND RptType in %s" % str(cls.SuperReportTypes), (userID, vin))
With this:
myrequests = Request.objects.filter(user=userID, vin = vin, report_type in cls.SuperReportTypes)
myrequests.aggregate(Max('Date'))
I get a:
SyntaxError: non-keyword arg after keyword arg (<console>, line 1)
When I remove the ending "report_type in cls.SuperReportTypes" the query functions properly.
I recognize that there is a way to do this after the query managing the result set but I was hoping to deal with this in such a way that MYSQL would do the execution.
field__in=seq
You are using the wrong in statement
https://docs.djangoproject.com/en/dev/ref/models/querysets/#in