【问题标题】:Conditionally Create Temp Table in SQL from Python从 Python 有条件地在 SQL 中创建临时表
【发布时间】:2021-09-03 11:31:49
【问题描述】:

在大量查询中,我尝试在 SQL 中创建一个临时表,如果它尚不存在的话。显然,您可以删除第二条CREATE TABLE 语句。但是,我正在构建的查询是动态的,可能存在也可能不存在第一个 CREATE TABLE 语句。

我可以让以下示例/测试查询在 Microsoft SQL Server Management Studio 中工作。它是在this SO question/answer的帮助下创建的

SET NOCOUNT ON;

DROP TABLE IF EXISTS #temp_sample;
CREATE TABLE #temp_sample (
    id VARCHAR(15) NOT NULL,
    datetime DATETIME,
    location VARCHAR(255)
);
GO 
    
INSERT INTO #temp_sample (id, datetime, location)
VALUES ('ABC', '2021-06-04 15:52:44', 'PENNSYLVANIA'),('123', '2021-06-04 15:52:49', 'PENNSYLVANIA');

IF (OBJECT_ID('tempdb..#temp_sample') IS NULL)
    BEGIN
        CREATE TABLE #temp_sample (
            id VARCHAR(15) NOT NULL,
            datetime DATETIME,
            location VARCHAR(255)
        );
    END
ELSE 
    PRINT '#temp_sample already exists... skipping'
GO

SELECT * FROM #temp_sample

当我在同一个数据库中运行以下代码,但使用 pandas.io.sql.read_sqlpypyodbc 时,我得到了随附的回溯:

import pypyodbc
import pandas.io.sql as psql

connection_string = 'DSN=dsn_name;UID=username;PWD=password;app=app_name;'
cnxn = pypyodbc.connect(connection_string)
temp_db_query = '''
    SET NOCOUNT ON;
       
    DROP TABLE IF EXISTS #temp_sample;
    CREATE TABLE #temp_sample (
        id VARCHAR(15) NOT NULL,
        datetime DATETIME,
        location VARCHAR(255)
    );
    GO

    INSERT INTO #temp_sample (id, datetime, location)
    VALUES ('ABC', '2021-06-04 15:52:44', 'PENNSYLVANIA'),('123', '2021-06-04 15:52:49', 'PENNSYLVANIA');

    IF (OBJECT_ID('tempdb..#temp_sample') IS NULL)
        BEGIN
            CREATE TABLE #temp_sample (
                id VARCHAR(15) NOT NULL,
                datetime DATETIME,
                location VARCHAR(255)
            );
        END
    ELSE
        PRINT '#temp_sample already exists... skipping'
    GO

    SELECT * FROM #temp_sample
'''

df = psql.read_sql(temp_db_query, cnxn)
cnxn.close()
Traceback (most recent call last):
    File "/Users/user/miniconda3/envs/myenv/lib/python3.6/site-packages/pandas/io/sql.py", line 1595, in execute 
        cur.execute(*args)
    File "/Users/user/miniconda3/envs/myenv/lib/python3.6/site-packages/pypyodbc.py", line 1626, in execute 
        self.execdirect(query_string)
    File "/Users/user/miniconda3/envs/myenv/lib/python3.6/site-packages/pypyodbc.py", line 1652, in execdirect 
        check_success(self, ret)
    File "/Users/user/miniconda3/envs/myenv/lib/python3.6/site-packages/pypyodbc.py", line 1007, in check_success
        ctrl_err(SQL_HANDLE_STMT, ODBC_obj.stmt_h, ret, ODBC_obj.ansi)
    File "/Users/user/miniconda3/envs/myenv/lib/python3.6/site-packages/pypyodbc.py", line 975, in ctrl_err
        raise ProgrammingError(state,err_text)
pypyodbc.ProgrammingError: ('42S01', "[42S01] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]There is already an object named '#temp_sample' in the database.")

有人可以帮助我使用pandas.io.sql.read_sql 使查询正常工作吗?我愿意切换到另一个 odbc 包,如 pyodbcturbodbc 等。

======= 更新 ========

基于其中一个 cmets,我尝试更改 IF 语句中的逻辑,因为在使用 ODBC 时,它似乎被标记为 TRUE。这个版本也适用于 MSSMS,但在 Python 中给了我同样的错误。是否有其他版本有效?

    IF EXISTS (SELECT * FROM tempdb.sys.tables WHERE name LIKE '#temp_sample%')
        PRINT '#temp_sample already exists... skipping'
    ELSE
        BEGIN
            CREATE TABLE #temp_sample (
                id VARCHAR(15) NOT NULL,
                datetime DATETIME,
                location VARCHAR(255)
            );
        END
    GO

【问题讨论】:

  • 你能把你的python代码添加到你的问题中吗?
  • 我按要求将python代码添加到问题中。
  • 删除所有GOstatements。另外,我没有看到IF (OBJECT_ID('tempdb..#temp_sample') IS NULL) 在 SQL 中测试 TRUE 的用例,它可能正在通过 ODBC 测试 FALSE
  • @Horaciux,我尝试删除所有 GO 语句并得到相同的结果。 IF 语句在 ODBC 中不返回 TRUE 很有趣,如果它是 FALSE 虽然它不应该再次尝试 CREATE 表...

标签: python sql pandas odbc temp-tables


【解决方案1】:

这是一个批处理编译错误。当您删除 GO 时,您必须这样做才能编译它,然后对于同一个临时表有两个 CREATE TABLE 语句,它们不会解析和编译。 EG这个批次产生同样的错误:

CREATE TABLE #temp_sample (id int)
if 1=0
begin
  CREATE TABLE #temp_sample (id int)
end

要修复,只需删除第二个CREATE TABLE,因为无论如何都没有必要。 EG

SET NOCOUNT ON;
   
DROP TABLE IF EXISTS #temp_sample;
CREATE TABLE #temp_sample (
    id VARCHAR(15) NOT NULL,
    datetime DATETIME,
    location VARCHAR(255)
);

INSERT INTO #temp_sample (id, datetime, location)
VALUES ('ABC', '2021-06-04 15:52:44', 'PENNSYLVANIA'),('123', '2021-06-04 15:52:49', 'PENNSYLVANIA');

SELECT * FROM #temp_sample

【讨论】:

  • 这个答案对我不起作用。我在上面提到过,问题中的示例查询实际上只是更大(动态生成)查询的一部分。在这种情况下,仅删除第二个 CREATE TABLE 不是可行的解决方案。对于这种情况,我需要在 IF 语句之前创建表是否已创建。
  • 然后您必须分批运行逻辑,就像 SSMS 在脚本中有 GO 时所做的那样。
猜你喜欢
  • 2013-03-19
  • 1970-01-01
  • 2011-11-03
  • 2011-03-28
  • 2021-03-18
  • 2019-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多