是否可以在Oracle过程中调用Python?我已经阅读了很多关于相反案例的文献(从Python调用Oracle SQL),但不是相反。
我想要做的是让Oracle生成一个数据库表,然后我想调用Python并在DataFrame中将这个数据库表传递给它,以便我可以使用Python对它做一些事情并产生结果。我可能需要在Oracle过程中多次调用Python。有谁知道这是否可能,怎么可能呢?
答案 0 :(得分:3)
嗯,答案很多,有一些非常好的选择,但让我尝试提出另一个答案。
让我们想象一下这种情况:
您始终可以做的就是使用PL/SQL
的API从DBMS_SCHEDULER
调用SHELL SCRIPTS。这些shell脚本可以调用您想要的任何东西,在本例中为Python程序。
我的情况如下:
让它起作用
SQL> create table t_python ( c1 number generated by default on null as identity ( start with 1 increment by 1 ) ,
c2 varchar2(10) ,
c3 date
) ;
Table created.
SQL> declare
begin
for r in 1..10
loop
insert into t_python values ( null , dbms_random.string('A','5') , sysdate - round(dbms_random.value(1,100),0) );
commit ;
end loop;
end;
/
PL/SQL procedure successfully completed.
SQL> select * from t_python
2 ;
C1 C2 C3
---------- ---------- ---------
1 Anrio 14-JUL-20
2 ouaTA 04-MAY-20
3 Swteu 06-JUL-20
4 kdsiZ 24-MAY-20
5 PXxbS 14-MAY-20
6 xQFYY 18-JUN-20
7 oahQR 09-MAY-20
8 ZjfXw 24-MAY-20
9 AmMOa 26-JUL-20
10 IQKpK 25-JUL-20
10 rows selected.
SQL>
因此,假设我在数据库中有一个函数,该函数返回一个SYS_REFCURSOR
对象,即一个集合或数据集。
SQL> CREATE OR REPLACE FUNCTION get_result_table_f RETURN SYS_REFCURSOR
AS
r_python SYS_REFCURSOR;
BEGIN
OPEN r_python FOR
SELECT
c1,
c2,
c3
FROM
t_python
ORDER BY
c1,
c2,
c3;
RETURN r_python;
END;
/
Function created
如果我在python程序中调用此函数,则效果很好。
import cx_Oracle
import pandas as pd
conn = cx_Oracle.connect('user/pwd@hostname:port/servicename')
cur = conn.cursor()
refCursor = cur.callfunc('get_result_table_f', cx_Oracle.CURSOR, [])
for row in refCursor:
print(row)
Result
$ /usr/bin/python3.6 /home/myuser/testcursor.py
(1, 'Anrio', datetime.datetime(2020, 7, 14, 12, 38, 52))
(2, 'ouaTA', datetime.datetime(2020, 5, 4, 12, 38, 52))
(3, 'Swteu', datetime.datetime(2020, 7, 6, 12, 38, 52))
(4, 'kdsiZ', datetime.datetime(2020, 5, 24, 12, 38, 52))
(5, 'PXxbS', datetime.datetime(2020, 5, 14, 12, 38, 52))
(6, 'xQFYY', datetime.datetime(2020, 6, 18, 12, 38, 52))
(7, 'oahQR', datetime.datetime(2020, 5, 9, 12, 38, 52))
(8, 'ZjfXw', datetime.datetime(2020, 5, 24, 12, 38, 52))
(9, 'AmMOa', datetime.datetime(2020, 7, 26, 12, 38, 52))
(10, 'IQKpK', datetime.datetime(2020, 7, 25, 12, 38, 52))
那么,如何在oracle过程中调用此python程序?
好吧,我的选择是使用DBMS_SCHEDULER的API,该API仅需要一个shell脚本来调用python程序。为了设置DBMS_SCHEDULER
,您只需要:
这就是它的样子
create or replace procedure run_python_program
as
v_job_count pls_integer;
v_owner varchar2(30);
v_job varchar2(120) := 'MY_PYTHON_SCRIPT';
begin
select count(*) into v_job_count from dba_scheduler_jobs where job_name = v_job ;
if v_job_count > 0
then
DBMS_SCHEDULER.drop_job (job_name=> v_job , force => true);
end if;
DBMS_SCHEDULER.create_job
(
job_name => v_job,
job_type => 'EXTERNAL_SCRIPT',
job_action => '/home/myuser/my_shell_script.sh `date +%Y%m%d`',
credential_name => 'ftpcpl',
enabled => FALSE
);
DBMS_SCHEDULER.run_job (job_name=> v_job, use_current_session => true);
exception when others then raise;
end;
/
您的shell脚本看起来很简单
#/bin/bash
odate=$1
logfile=/home/myuser/logfile_$odate.txt
/usr/bin/python3.6 /home/myuser/testpython.py >> $logfile
运行过程
SQL> begin
run_python_program;
end;
/
PL/SQL procedure successfully completed.
SQL> host cat /home/test/logfile_20200809.txt
(1, 'Anrio', datetime.datetime(2020, 7, 14, 12, 38, 52))
(2, 'ouaTA', datetime.datetime(2020, 5, 4, 12, 38, 52))
(3, 'Swteu', datetime.datetime(2020, 7, 6, 12, 38, 52))
(4, 'kdsiZ', datetime.datetime(2020, 5, 24, 12, 38, 52))
(5, 'PXxbS', datetime.datetime(2020, 5, 14, 12, 38, 52))
(6, 'xQFYY', datetime.datetime(2020, 6, 18, 12, 38, 52))
(7, 'oahQR', datetime.datetime(2020, 5, 9, 12, 38, 52))
(8, 'ZjfXw', datetime.datetime(2020, 5, 24, 12, 38, 52))
(9, 'AmMOa', datetime.datetime(2020, 7, 26, 12, 38, 52))
(10, 'IQKpK', datetime.datetime(2020, 7, 25, 12, 38, 52))
请记住,我做了一个非常简单的测试,只是向您展示了如何从PL / SQL调用python(嵌入到shell脚本中)。实际上,您可以使该过程运行多个外部脚本(python程序),并且可以通过多种方式与数据进行交互。
例如,您可以执行以下操作:
依此类推。
实际上,我在Shell脚本中有很多程序,这些程序是使用Oracle Scheduler Chains分步执行的。这些步骤之一实际上是一个python程序。我发现DBMS_SCHEDULER
的API在您需要从PL / SQL中运行技术时非常有用,只要可以使用Shell脚本(或Windows中的cmd)来调用它们即可。
答案 1 :(得分:2)
你可以write stored procedures in Java而你可以use Java to run Python code,这样你就可以将两者结合起来实现你想要的目标。
答案 2 :(得分:2)
在边缘,有可能如何克服PL / SQL限制。 您可以在Database和Python程序之间设计特定的接口。 我想你可以使用Python的一个库来从网上获取一些数据。 然后使用C库与Oracle交换数据。
使用c库调用python - >数据文件 - >外部表 - >数据
注意:将其作为概念证明,或者更深入探索的起点。另外,我强烈反对你不要在生产中使用它。打破PL / SQL监狱来调用系统程序至少可以认为是不安全的。
所以这是如何进行的可能方式:
- == Prerequisities == -
pip install quandl
- == quandl.py == -
#!/usr/bin/python
import quandl
# World Bank Education Statistics
# Population, tertiary, total - Czech Republic
data = quandl.get("WEDU/CZE_SP_TER_TOTL_IN")
data.to_csv("/u01/data/data.txt")
- == exec.c == -
//
// gcc -Wall -fPIC -c exec.c
// gcc -shared -o exec.so exec.o
// mkdir -p /u01/lib
// cp exec.so /u01/lib
//
#include <stdlib.h>
int execute() {
system("/u01/bin/get_data.py");
return 0; // We want to make the compiler happy
}
- == LISTENER CONFIGURATION == -
SID_LIST_LISTENER =
...
(SID_DESC =
...
(ENVS="EXTPROC_DLLS=ANY")
(PROGRAM = extproc)
...
- == DDL PART == -
create or replace library c_exec is '/u01/lib/exec.so';
create or replace procedure exec as external
name "execute"
library c_exec
language c;
/
create directory pydata as '/u01/data';
create table data (
"date" varchar2(14),
"value" varchar2(32)
) organization external (
type oracle_loader
default directory pydata
access parameters (
records delimited by newline
nobadfile nodiscardfile nologfile
fields terminated by ','
) location (pydata:'data.txt')
);
--- === USAGE === ---
- ==下载处理数据== -
使用外部PL / SQL C库您可以调用python程序将结果存储到外部表的预期位置。
execute exec;
- ==查询数据== -
select
to_date("date",'yyyy-mm-dd') "date",
to_number("value") "value"
from data
where "date" != 'Date';
- ==结果== -
date value
--------- ----------
31-DEC-70 886414
31-DEC-71 885549
31-DEC-72 877533
31-DEC-73 862859
答案 3 :(得分:1)
我想这是不可能的,因为PL / SQL是专为在Oracle服务器内快速执行而设计的,由于内部限制,这不是其他供应商的任意代码可能的地方。
OTOH您可以通过TCP通道从存储过程与另一台服务器进行交互,this page是指UTL_TCP包。在外部网络服务器中,您可以使用任何语言和任何逻辑。
答案 4 :(得分:1)
根据要使用Python的上下文,可以考虑 OML4Py :
主要优点:
数据库内处理:“移动算法,而不是数据!”-处理数据所在的位置以消除数据移动,并进一步利用Oracle环境作为具有并行功能的高性能计算引擎,分布式算法。
快速部署机器学习应用程序-由于数据库内机器学习模型是本机SQL函数,因此可以通过SQL和R脚本立即进行模型部署。
进一步阅读:
Oracle Machine Learning: Scaling R and Python for the Enterprise
幻灯片(回答此特定问题):
Oracle Machine Learning Platform Move the algorithms, not the data!
答案 5 :(得分:0)
您可以对外部表使用预处理器功能,该功能允许您调用Python脚本以用数据填充外部表。可以在此OTN文章的“使用外部表”部分找到一个示例:https://community.oracle.com/docs/DOC-994731。
答案 6 :(得分:0)
有点复杂但可能。我见过一次。您需要