【问题标题】:Anyone know why I am getting this error when trying to load dataframe to sybase table? [sql alchemy]任何人都知道为什么在尝试将数据帧加载到 sybase 表时出现此错误? 【sql炼金术】
【发布时间】:2019-01-06 02:50:58
【问题描述】:

我正在尝试将一个 pandas 数据帧附加到已创建的表中,但我不断收到错误消息。

我正确连接到服务器。服务器内部有很多数据库,那么这个表就在db_STAFF数据库里面。最初,我在做df.to_sql(db_STAFF.dbo.JUNESALES),但我意识到我应该在 connString 中引用它。我试过dbo.JUNESALES 以及JUNESALES。下面错误中的表名称会根据我所说的表(dbo.JUNESALES 与 JUNESALES)而变化,但实际错误保持不变。

请参阅下面的代码和错误,减去我确实包含的导入语句。

df = pd.DataFrame(lists_data)
connString = "DRIVER={Adaptive Server Enterprise};SERVER=XXXX,DATABASE = 'db_STAFF'...."
conn_url = quote_plus(connString)
new_connection = "sybase+pyodbc:///?odbc_connect={}".format(conn_url)
engine = create_engine(new_connection)
df.to_sql('[dbo].[JUNESALES]', con=engine, if_exists = 'append', index = False) #I also tried this without the brackets, I read that with brackets it worked for someone 
engine.execute("SELECT * FROM dbo.JUNESALES ").fetchall()
cursor.execute(statement, parameters)

我在df.to_sql 行收到此错误

sqlalchemy.exc.ProgrammingError: (pyodbc.ProgrammingError) ('42000', "[42000] [Sybase][ODBC Driver][Adaptive Server Enterprise] Incorrect syntax near '('.\n (102) (SQLExecDirectW)") [SQL: '\nCREATE TABLE "[dbo].[JUNESALES]" (\n\t"0" BIGINT NULL, \n\t"1" BIGINT NULL, \n\t"2" FLOAT NULL, \n\t"3" TEXT NULL, \n\t"4" BIT NULL,  \n\t"5" BIT NULL, \n\t"6" FLOAT NULL, \n\t"7" FLOAT NULL, \n\t"8" FLOAT NULL, \n\t"9" FLOAT NULL, \n\t"10" FLOAT NULL, \n\t"11" BIGINT NULL, \n\tCHECK ("4" IN (0, 1)), \n\tCHECK ("5" IN (0, 1))\n)\n\n'] (Background on this error at: http://sqlalche.me/e/f405)

【问题讨论】:

  • “错误是一个段落,我只是为了更容易阅读而将这些行分开”-请不要那样做。准确的错误消息格式通常非常重要,even down to individual space characters。
  • 我可以解决这个问题@user2357112
  • 现在一段@user2357112
  • 我很确定to_sql 的第一个参数应该只是表名——没有数据库或模式信息,也没有括号。 (ASE 甚至使用方括号来转义标识符吗?我认为不会。)

标签: python pandas sqlalchemy sybase sap-ase


【解决方案1】:

注意:我是 Sybase ASE DBA;我不使用 python/pandas/sqlalchemy/etc;所以虽然我可以告诉你为什么 ASE 会产生错误,甚至向你展示一种正确格式化create table 命令的方法......我不知道如何告诉你的应用程序如何(重新)编码@987654322 @ 命令(假设这是您无法直接控制的)。

错误消息告诉我们create table 命令如下所示:

CREATE TABLE "[dbo].[JUNESALES]" (
        "0" BIGINT NULL,
        "1" BIGINT NULL,
        "2" FLOAT NULL,
        "3" TEXT NULL,
        "4" BIT NULL,
        "5" BIT NULL,
        "6" FLOAT NULL,
        "7" FLOAT NULL,
        "8" FLOAT NULL,
        "9" FLOAT NULL,
        "10" FLOAT NULL,
        "11" BIGINT NULL,
        CHECK ("4" IN (0, 1)),
        CHECK ("5" IN (0, 1))
)

嗯嗯,从哪里开始……

如果您要将其剪切并粘贴到 ASE 会话中(例如,通过 isql 命令行工具),您将收到相同的错误:

Msg 102, Level 15, State 181:
Server 'ASE200', Line 2:
Incorrect syntax near '('.

该命令似乎使用双引号来试图转义非标准标识符。这样做的一个问题是,默认情况下,ASE 不将双引号识别为非标准标识符的转义字符。要解决这个问题,您需要启用quoted_identifier,例如:

set quoted_identifier on

CREATE TABLE ...
... snip ...

set quoted_identifier off -- or leave 'on' if you're going to continue using double quotes to designate non-standard identifiers
go

虽然这会让您摆脱 Msg 102(语法)错误,但您现在会遇到一些新错误:

Msg 2718, Level 16, State 1:
Server 'ASE200', Line 2:
Column or parameter #5:  -- can't specify Null values on a column of type BIT.
Msg 2718, Level 16, State 1:
Server 'ASE200', Line 2:
Column or parameter #6:  -- can't specify Null values on a column of type BIT.

要修复这些错误,您需要将 BIT 列指定为 NOT NULL 或将数据类型更改为 BIT 以外的其他内容(例如,tinyint? 尽管您现在可能需要添加一些应用程序代码或check 约束将合法值限制为 0/1 ...??):

set quoted_identifier on

CREATE TABLE ...
... snip ...
        "4" BIT not NULL,
        "5" BIT not NULL,
... snip ...

set quoted_identifier off
go

此时应该创建表(即,没有错误)但是......你还没有走出困境。

如果您运行sp_help,您会看到您的表格如下所示:

sp_help
go

 Name                        Owner Object_type
 --------------------------- ----- ------------
 ... snip ...
 [dbo].[JUNESALES]           dbo   user table
 ... snip ...

这里的问题(当然?)是您将所有者 and 表包含在一对双引号中;并且您尝试使用 2 种不同的方法来处理非标准标识符也无济于事……双引号……方括号;这里的主要问题是双引号告诉 ASE,方括号实际上是称为 [dbo].[JUNESALES] 的单个标识符的一部分;还要注意句点 (.) 也被视为单个标识符的一部分(而不是所有者和表名之间的分隔符)。

如果您尝试通过在 [dbo] 和 [JUNESALES] 周围加上双引号来修复他,那么您会收到以下错误消息:

set quoted_identifier on

CREATE TABLE "[dbo]"."[JUNESALES]"
... snip ...
go

Msg 2734, Level 16, State 1:
Server 'ASE200', Line 2:
User name [dbo] does not exist in sysusers.

    !!! notice the square brackets are considered as part of the user name !!!

好的,我们可以通过从[dbo] 中删除方括号来解决此问题,但如果您不对表名执行相同操作...create table 命令成功,但方括号会成为表的一部分名称(而不是用作分隔符),例如:

set quoted_identifier on
CREATE TABLE "dbo"."[JUNESALES]"
... snip ...
go

sp_help
go

 Name                        Owner Object_type
 --------------------------- ----- ------------
 ... snip ...
 [JUNESALES]                 dbo   user table
 ... snip ...

ASE 支持使用双引号作为非标准标识符的分隔符...如果您首先发出set quoted_identifier on。

ASE 还支持使用方括号作为非标准标识符的分隔符...并且无需发出set quoted_identier on 命令。

我建议您弄清楚如何仅使用一种方法来分隔非标准标识符(方括号更简洁,不需要发出set quoted_identifier on,并允许您使用双引号来分隔文本/字符数据)。

set quoted_identifier off  -- optional if already set to 'off'

CREATE TABLE [dbo].[JUNESALES] (
        [0] BIGINT NULL,
        [1] BIGINT NULL,
        [2] FLOAT NULL,
        [3] TEXT NULL,
        [4] BIT not NULL,
        [5] BIT not NULL,
        [6] FLOAT NULL,
        [7] FLOAT NULL,
        [8] FLOAT NULL,
        [9] FLOAT NULL,
        [10] FLOAT NULL,
        [11] BIGINT NULL,
        CHECK ([4] IN (0, 1)),
        CHECK ([5] IN (0, 1))
)
go

sp_help
go

 Name                        Owner Object_type
 --------------------------- ----- ------------
 ... snip ...
 JUNESALES                   dbo   user table
 ... snip ...

当然,dbo 和 JUNESALES 周围的分隔符不是必需的(即,它们是有效的标识符),但如果您愿意,欢迎使用方括号(例如,作为标准编码方法用于处理所有分隔符,无论是标准的还是非标准的)。

注意:以上代码 sn-ps 是针对 ASE 15.7 (SP138) 数据服务器执行的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 2021-12-24
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    相关资源
    最近更新 更多