【问题标题】:Python cx_Oracle module: unable to format query in codePython cx_Oracle 模块:无法在代码中格式化查询
【发布时间】:2021-02-24 07:20:37
【问题描述】:

我正在使用 cx_Oracle 模块连接到 oracle 数据库。在脚本中,我使用了两个变量 schema_name 和 table_name。下面的查询工作正常

cur1.execute("select owner,table_name from dba_tables where owner ='schema_name'")

但是我需要查询一个表的行数,我需要用 schema_name 来限定 table_name,所以查询应该是

SELECT count(*) FROM "schema_name"."table_name"

这在代码中使用时不起作用,我尝试将其放在三引号、单引号和其他选项中,但它没有按预期格式化查询,因此不存在表错误。

感谢任何指导。

【问题讨论】:

    标签: python oracle boto3 cx-oracle


    【解决方案1】:

    可以使用包含占位符的预准备语句,变量形式为...{}.{}".format(sc,tb)

    sc='myschema'
    tb='mytable'
    
    cur1.execute("SELECT COUNT(*) FROM {}.{}".format(sc,tb))
    print(cur1.fetchone()[0])
    

    【讨论】:

    • 很好的解决方案。但我对这种情况下的术语持怀疑态度:“绑定变量”的使用不是 Oracle 对绑定变量的定义。 Oracle 的绑定变量是一种将数据与代码分开的方法。使用这个 sn-p,根据已知的“安全”列表验证 sc 和 tb 值仍然很重要。
    • 感谢@ChristopherJones 你是对的,修正了解释。
    • 您也可以使用 f-strings,如 cur1.execute(f"select count(*) from {sc}.{tb}") —— 但如前所述,您需要确保 sc 和 tb 的值是已知的或经过验证的。
    【解决方案2】:

    在这种特殊情况下,您也可以尝试设置Connection.current_schema,参见cx_Oracle API doc

    例如,如果您在自己的架构中创建表:

    SQL> show user
    USER is "CJ"
    SQL> create table ffff (mycol number);
    
    Table created.
    
    SQL> insert into ffff values (1);
    
    1 row created.
    
    SQL> commit;
    
    Commit complete.
    

    然后运行以不同用户身份连接的 Python 代码:

    import cx_Oracle
    import os
    
    import sys, os
    if sys.platform.startswith("darwin"):
        cx_Oracle.init_oracle_client(lib_dir=os.environ.get("HOME")+"/Downloads/instantclient_19_8")
    
    username = "system"
    password = "oracle"
    connect_string = "localhost/orclpdb1"
    
    connection = cx_Oracle.connect(username, password, connect_string)
    
    connection.current_schema = 'CJ';
    
    with connection.cursor() as cursor:
        sql = """select * from ffff"""
        for r in cursor.execute(sql):
            print(r)
    
        sql = """select sys_context('USERENV','CURRENT_USER') from dual"""
        for r in cursor.execute(sql):
            print(r)
    

    输出将是:

    (1,)
    ('SYSTEM',)
    

    最后一个查询表明被改变的不是用户,而是第一个查询自动从'ffff'变为'CJ.ffff'。

    【讨论】:

    • 感谢 Christopher,我尝试在我的代码中使用它,但我发现即使在将架构设置为我想要的之后,当我尝试查询架构中存在的表时,它说表不存在而且当我尝试查询当前用户时,它显示管理员,这是建立数据库连接的用户,而不是使用 Connection.current_schema 设置的用户。
    • ``` schema_name='myschemaname' table_name='mypassword' dsn_tns1 = cx_Oracle.makedsn(db_host,db_port,db_name) conn1 = cx_Oracle.connect(user=username, password=password, dsn=dsn_tns1 ) cur1 = conn1.cursor() conn1.current_schema = schema_name cur1.execute("SELECT COUNT(*) FROM {}".format(table_name)) print(cur1.fetchall()) cur1.execute("select sys_context(' USERENV','CURRENT_USER') 来自双重") ```
    • 感谢 Christopher,出于测试目的,我在模式测试中创建了一个表测试,它工作正常。但是,当我查询名称中带有下划线的实际表时,代码会失败。我认为这与必须用双引号括起来的表名有关。即使在 sqlplus 中,当我查询表时 select * from test.test 它工作正常,但是当我查询 select * from scheme.table_name 它失败时,我必须在双引号中指定 table_name
    猜你喜欢
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 2012-10-30
    • 1970-01-01
    相关资源
    最近更新 更多