Update multiple column with bind variable using cx_Oracle.executemany() - python-3.x

I have been trying to update some columns of a database table using cx_Oracle in Python. I created a list named check_to_process which is a result of another sql query. I am creating log_msg in the program based on success or failure and want to update same in the table only for records in check_to_process list. When I update the table without using bind variable <MESSAGE = %s>, it works fine. But when I try to use bind variable to update the columns it gives me error :
cursor.executemany("UPDATE apps.SLCAP_CITI_PAYMENT_BATCH SET MESSAGE = %s, "
TypeError: an integer is required (got type str)
Below is the code, I am using:
import cx_Oracle
connection = cx_Oracle.connect(user=os.environ['ORA_DB_USR'], password=os.environ['ORA_DB_PWD'], dsn=os.environ['ORA_DSN'])
cursor = connection.cursor()
check_to_process = ['ACHRMUS-20-OCT-2021 00:12:57', 'ACHRMUS-12-OCT-2021 16:12:01']
placeholders = ','.join(":x%d" % i for i,_ in enumerate(check_to_process))
log_msg = 'Success'
cursor.executemany("UPDATE apps.SLCAP_CITI_PAYMENT_BATCH SET MESSAGE = %s, "
"PAYMENT_FILE_CREATED_FLAG='N' "
"WHERE PAYMENT_BATCH_NAME = :1",
[(i,) for i in check_to_process], log_msg, arraydmlrowcounts=True)
Many thanks for suggestions and insights!

Your code has an odd mix of string substitution (the %s) and bind variable placeholders (the :1). And odd code that creates bind variable placeholders that aren't used. Passing log_msg the way you do isn't going to work, since executemany() syntax doesn't support string substitution.
You probably want to use some kind of IN list, as shown in the cx_Oracle documentation Binding Multiple Values to a SQL WHERE IN Clause. Various solutions are shown there, depending on the number of values and frequency that the statement will be re-executed.
Use only bind variables. You should be able to use execute() instead of executemany(). Effectively you would do:
cursor.execute("""UPDATE apps.SLCAP_CITI_PAYMENT_BATCH
SET MESSAGE = :1
WHERE PAYMENT_BATCH_NAME IN (something goes here - see the doc)""",
bind_values)
The bottom line is: read the documentation and review examples like batch_errors.py. If you still have problems, refine your question, correct it, and add more detail.

Related

MySQL Connector SQL Query using LIKE

I have two sets of similar codes that gives different output. The first example does not return any output but the second example returns a output using the same search input.
First Example:
sql = "SELECT accessionID, title, ISBN, publisher, publicationYear FROM Books WHERE %s LIKE %s";
cursor.execute(sql,(col, "%" + values + "%",))
Second Example:
sql = "SELECT accessionID, title, ISBN, publisher, publicationYear FROM Books WHERE title LIKE %s";
cursor.execute(sql,("%" + values + "%",))
The codes that I am trying to code out is that WHERE is dynamic that depends on which text field user searches on. For example, if a user searches something on the title text box, it will only look into Title.
Another way I could think of is to use If conditions to hardcode, but it only works for the first If conditions and subsequent one does not work.
My question is how to make the SQL line dynamic (using first example) in the sense that I can do two %s in the SQL query line and still get the same output?

What is the best way to pass multiple string variables to a query string in python3

I need to create a dynamic query based on two string parameters:
description = "This is the description"
comment = "This is the comment"
query = "insert into case(desc, comm) value(description, comment)"
Note:
there might be single quote and double quotes in both description and comment.
How do I use formatted %s to generate the query string?
Thank you very much.
UPDATE:
Thanks to Green Cloak Guy (his/her answer has minors to be corrected), the right query is:
query = f"insert into case(description, comment) value(\'{description}\', \'{comment}\')"
Use an f-string.
query = f"insert into case({description}, {comment}) value({description}, {comment})"
Don't use any type of string formatting to do actual database queries - that leads to you having a SQL Injection problem. Use a database library instead, that properly sanitizes the data.
But if all you need to do is parse some variables into a string, this is more flexible than the % formatting that other languages tend to use (and that's technically still available in python via "some_string %s %s %s" % (str1, str2, str3)")

Pass in SQL query the table name as parameter

A possible solution for this question is here:
https://stackoverflow.com/a/6223961/12343395
It will probably work with a lot of work around.
But I have stored my table names in string format and want to call them as needed.
I am using Pandas read_sql_query. So as in params, I am passing, the table name and a few parameters in the WHERE section.
The WHERE section is fine, since the parameters are originally strings. But in the FROM section,
I really want the schema.table as a non-string.
Here is a snippet.
SELECT "rainfall(mm)","tmin(C)","tmax(C)","TimeStamp"
FROM crop_tables[choose_crop][0]
WHERE "District_Name" = %s AND "Season" = %s
ORDER BY "TimeStamp" ASC
where crop_tables[choose_crop][0] is 'sagita_historic.soyabean_daily_analyses' in this case.
But FROM will throw an error since it doesn't accept strings. So in essence, I wish to strip the 'sagita_historic.soyabean_daily_analyses' as a non-string.
Is it possible to do so?
Thank you.
Not sure I fully understand but maybe this will do?
SELECT "rainfall(mm)","tmin(C)","tmax(C)","TimeStamp"
FROM f"{crop_tables[choose_crop][0]}"
WHERE "District_Name" = %s AND "Season" = %s
ORDER BY "TimeStamp" ASC

Condition IF In Power Query's Advanced Editor

I have a field named field, and I would like to see if it is null, but I get an error in the query, my code is this:
let
Condition= Excel.CurrentWorkbook(){[Name="test_table"]}[Content],
field= Condition{0}[fieldColumn],
query1="select * from students",
if field <> null then query1=query1 & " where id = '"& field &"',
exec= Oracle.Database("TESTING",[Query=query1])
in
exec
but I get an error in the condition, do you identify the mistake?
I got Expression.SyntaxError: Token Identifier expected.
You need to assign the if line to a variable. Each M line needs to start with an assignment:
let
Condition= Excel.CurrentWorkbook(){[Name="test_table"]}[Content],
field= Condition{0}[fieldColumn],
query1="select * from students",
query2 = if field <> null then query1 & " some stuff" else " some other stuff",
exec= Oracle.Database("TESTING",[Query=query2])
in
exec
In query2 you can build the select statement. I simplified it, because you also have conflicts with the double quotes.
I think you're looking for:
if Not IsNull(field) then ....
Some data types you may have to check using IsEmpty() or 'field is Not Nothing' too. Depending on the datatype and what you are using.
To troubleshoot, it's best to try to set a breakpoint and locate where the error is happening and watch the variable to prevent against that specific value.
To meet this requirement, I would build a fresh Query using the PQ UI to select the students table/view from Oracle, and then use the UI to Filter the [id] column on any value.
Then in the advanced editor I would edit the generated FilteredRows line using code from your Condition + field steps, e.g.
FilteredRows = Table.SelectRows(TESTING_students, each [id] = Excel.CurrentWorkbook(){[Name="test_table"]}{0}[fieldColumn])
This is a minor change from a generated script, rather than trying to write the whole thing from scratch.

How does CqlConfigHelper.setOutputCql() work?

I am following the hadoop_cql3_word_count example in Cassandra and have questions with the following code segment:
String query =
"UPDATE " + KEYSPACE + "." + OUTPUT_COLUMN_FAMILY +
" SET count_num = ? ";
CqlConfigHelper.setOutputCql(job.getConfiguration(), query);
My questions are:
What is the definition of the question mark (i.e., ?) in the above query? Does Cassandra process it in a way such that the question mark is replaced by some value?
If I would like to update multiple columns of a row given its key, how should I modify the above update statement?
Thank you,
The ? represents a slot for a variable in a prepared statement. When your MR job completes the values will be placed into the ?s in order.
If your MR results looked like (key=key1, 1) (key=key2, 2) (key=key3, 3)
Then the statements executed would be
Update Keyspace.columnfamily SET count_num = 1 where key=key1
Update Keyspace.columnfamily SET count_num = 2 where key=key2
Update Keyspace.columnfamily SET count_num = 3 where key=key3
To update multiple columns you just need to write a larger prepared statement and make sure your map reduce job is providing all of the appropriate values.
In the WC example
keys.put("row_id1", ByteBufferUtil.bytes(partitionKeys[0]));
keys.put("row_id2", ByteBufferUtil.bytes(partitionKeys[1]));
...
keys.put("word", ByteBufferUtil.bytes(word.toString()));
variables.add(ByteBufferUtil.bytes(String.valueOf(sum)));
...
context.write(keys, getBindVariables(word, sum));
This makes the reducer output look like
({row_id1=1,row_id2=3,word=pizza},4)
And the prepared statement will be executed like
UPDATE cql3_worldcount.output_words SET count_num = 4 where row_id1=1 AND row_id2=3 AND word=pizza ;
If I wanted a prepared statement with multiple columns it would look like
UPDATE test SET a =?,b=?,c=?,d=? (This gets filled in by the connector: where key=...)
With a real prepared statement we would also fill in the key as well, but here the connector to Cassandra will just use whatever mappings you have in your reducer output.
({key='mykey'},(1,2,3,4))
becomes
UPDATE test SET a =1,b=2,c=3,d=4 where key=mykey
For more information on prepared statements in general check
SO Question about Prepared Statements in CQL

Resources