It's - for sqlplus - commands:
SQL> set serveroutput on
SQL> exec where.my_package.ger_result('something');
something=1823655138
And it's - for cx_Oracle:
>>> c.callproc('where.my_package.ger_result', ('something',))
['something']
As You can see - the results are different.
I have no idea, how to fix it. :[
import cx_Oracle
dsn_tns = cx_Oracle.makedsn('my_ip_address_server_next_port', 0000, 'sid')
db = cx_Oracle.connect('user', 'password', dsn_tns)
curs = db.cursor()
curs.callproc("dbms_output.enable")
curs.callproc('where.my_package.ger_result', ['something',])
statusVar = curs.var(cx_Oracle.NUMBER)
lineVar = curs.var(cx_Oracle.STRING)
while True:
curs.callproc("dbms_output.get_line", (lineVar, statusVar))
if statusVar.getvalue() != 0:
break
print lineVar.getvalue()
Sorry, I can't reproduce this one.
I don't have your PL/SQL package, so I used the following stored procedure instead:
CREATE OR REPLACE PROCEDURE p_do_somet (
p_param IN VARCHAR2
) AS
BEGIN
dbms_output.put_line(p_param || '=1823655138');
END;
/
I got the same output, something=1823655138, from SQL*Plus and from using the Python script in your answer.
If you're getting different results using SQL*Plus and cx_Oracle, then either your stored procedure is doing something very funny (I don't know what could cause it to do this), or your SQL*Plus session and Python script are not connecting to the same database and/or schema.
Related
I'm using Jupyter notebook to run a PL/SQL script but I get an error. The code block in the notebook is as follows:
%%sql
DECLARE BEGIN
FOR record_item IN (
SELECT
*
FROM
duplicated_records
) LOOP
EXECUTE IMMEDIATE 'UPDATE table_name SET record_id ='|| record_item.original_record_id || ' WHERE record_id =' || record_item.duplicated_record_id;
EXECUTE IMMEDIATE 'DELETE FROM records WHERE id ='|| record_item.duplicated_record_id;
END LOOP;
END
The error is
(cx_Oracle.DatabaseError) ORA-06550: line 8, column 165:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
Non-PL/SQL code, such as select, and update statements, seems to work.
It works perfectly fine with other SQL clients like SQL developer. I've tried adding/removing the; at the end but it still doesn't work.
I don't know Python so I can't assist about that, but - as far as Oracle is concerned - you don't need DECLARE (as you didn't declare anything), and you certainly don't need dynamic SQL (EXECUTE IMMEDIATE) as there's nothing dynamic there.
Rewritten:
BEGIN
FOR record_item IN (SELECT * FROM duplicated_records) LOOP
UPDATE table_name
SET record_id = record_item.original_record_id
WHERE record_id = record_item.duplicated_record_id;
DELETE FROM records
WHERE id = record_item.duplicated_record_id;
END LOOP;
END;
On the other hand, row-by-row processing is slow-by-slow. Consider using two separate statements: one which will update existing rows, and another which will delete rows (from a different table, apparently):
merge into table_name a
using duplicated_records b
on (a.record_id = b.duplicate_record_id)
when matched then update set
a.record_id = b.original_record_id;
delete from records a
where a.id in (select b.duplicated_record_id from duplicated_records b);
If tables are properly indexed (on ID columns), that should behave better (faster).
The direct implementation of your code in Python would be like:
import oracledb
import traceback
import os
import sys
#if sys.platform.startswith('darwin'):
# oracledb.init_oracle_client(lib_dir=os.environ.get('HOME')+'/Downloads/instantclient_19_8')
un = os.environ.get('PYTHON_USERNAME')
pw = os.environ.get('PYTHON_PASSWORD')
cs = os.environ.get('PYTHON_CONNECTSTRING')
try:
connection = oracledb.connect(user=un, password=pw, dsn=cs)
with connection.cursor() as cursor:
plsql = """BEGIN
FOR RECORD_ITEM IN (
SELECT
*
FROM
DUPLICATED_RECORDS
) LOOP
EXECUTE IMMEDIATE 'UPDATE table_name SET record_id ='
|| RECORD_ITEM.ORIGINAL_RECORD_ID
|| ' WHERE record_id ='
|| RECORD_ITEM.DUPLICATED_RECORD_ID;
EXECUTE IMMEDIATE 'DELETE FROM records WHERE id ='
|| RECORD_ITEM.DUPLICATED_RECORD_ID;
END LOOP;
END;"""
cursor.execute(plsql)
except oracledb.Error as e:
error, = e.args
traceback.print_tb(e.__traceback__)
print(error.message)
For this you need to install the oracledb module, which is the renamed, latest version of the cx_Oracle module. It will work with cx_Oracle by changing the import to import cx_Oracle as oracledb.
However, before blindly copying this, check #littlefoot's answer for more about the PL/SQL code.
Stored Procedure :
CREATE OR REPLACE FUNCTION try_create() RETURNS INT AS $$
BEGIN
CREATE TABLE hello(id SERIAL PRIMARY KEY, name TEXT);
RETURN 1;
END ;
$$ LANGUAGE plpgsql;
test.py
import psycopg2
conn = psycopg2.connect(user='a', password='a', dbname='a')
cur = conn.cursor()
cur.callproc('try_create', ())
print cur.fetchall()
I am trying to create a stored procedure which will create a table named hello. I am invoking the same using a python script. Upon running the above script I see the following output
[root#localhost partitioning]# python test.py
[(1,)]
But the table is not created at the db. Am I making something wrong here? Thanks.
You should commit the transaction, add the commands:
...
conn.commit()
conn.close()
Alternatively, you can set the connection in autocommit mode:
conn = psycopg2.connect(user='a', password='a', dbname='a')
conn.autocommit = True
cur = conn.cursor()
cur.callproc('try_create', ())
conn.close()
Read more about transactions in psycopg2.
I have installed mysql for python and running python from command line. I am getting syntax error while creating a database.
>>> import MySQLdb
>>> CREATE DATABASE chom;
File "<stdin>", line 1
CREATE DATABASE chom;
^
SyntaxError: invalid syntax
CREATE DATABASE chom; this should be run from the MySQL command line client, not from the Python shell.
So, first type mysql -u yourusername -p from your command line. It will ask you for a password, type it in. Then you will get a prompt like this mysql>. Here is where you would type that query.
Now, if you want to do this through Python, you can, but it will require some more work.
>>> import MySQLdb as db
>>> con = db.connect(user="foo", passwd="secret")
>>> cur = con.cursor()
>>> cur.execute('CREATE DATABASE chom;')
See this guide for some examples on how to work with Python and MySQL using the standard DB API.
If you want create a database,you can try:
import MySQLdb
db1 = MySQLdb.connect(host="localhost",user="root",passwd="****")
cursor = db1.cursor()
sql = 'CREATE DATABASE chom'
cursor.execute(sql)
My simple test code is listed below. I created the table already and can query it using the SQLite Manager add-in on Firefox so I know the table and data exist. When I run the query in python (and using the python shell) I get the no such table error
def TroyTest(self, acctno):
conn = sqlite3.connect('TroyData.db')
curs = conn.cursor()
v1 = curs.execute('''
SELECT acctvalue
FROM balancedata
WHERE acctno = ? ''', acctno)
print v1
conn.close()
When you pass SQLite a non-existing path, it'll happily open a new database for you, instead of telling you that the file did not exist before. When you do that, it'll be empty and you'll instead get a "No such table" error.
You are using a relative path to the database, meaning it'll try to open the database in the current directory, and that is probably not where you think it is..
The remedy is to use an absolute path instead:
conn = sqlite3.connect('/full/path/to/TroyData.db')
You need to loop over the cursor to see results:
curs.execute('''
SELECT acctvalue
FROM balancedata
WHERE acctno = ? ''', acctno)
for row in curs:
print row[0]
or call fetchone():
print curs.fetchone() # prints whole row tuple
The problem is the SQL statment. you must specify the db name and after the table name...
'''SELECT * FROM db_name.table_name WHERE acctno = ? '''
How can you fix the SQL-statement in Python?
The db connection works. However, cur.execute returns none which is false.
My code
import os, pg, sys, re, psycopg2
try:
conn = psycopg2.connect("dbname='tk' host='localhost' port='5432' user='naa' password='123'")
except: print "unable to connect to db"
cur = conn.cursor()
print cur.execute("SELECT * FROM courses") # problem here
The SQL-command in Psql returns me the correct output.
I can similarly run INSERT in Psql, but not by Python's scripts.
I get no warning/error to /var/log.
Possible bugs are
cursor(), seems to be right however
the syntax of the method connect(), seems to be ok however
You have to call one of the fetch methods on cur (fetchone, fetchmany, fetchall) to actually get the results of the query.
You should probably have a read through the a tutorial for DB-API.
You have to call cur.fetchall() method (or one of other fetch*() methods) to get results from query.