【问题标题】:Column does not exist (SQLAlchemy / PostgreSQL): Trouble with quotation marks列不存在(SQLAlchemy / PostgreSQL):引号有问题
【发布时间】:2021-10-08 15:27:30
【问题描述】:

我在使用 SQLAlchemy 进行 postgresql 查询时遇到问题。

我使用这行代码创建了一些大表:

frame.to_sql('Table1', con=engine, method='multi', if_exists='append')

效果很好。现在,当我想从中查询数据时,我的第一个问题是我必须为每个表和列名使用引号,我真的不知道为什么,也许有人可以帮助我。

不过,这不是我的主要问题。我的主要问题是,在查询数据时,所有数字 WHERE 条件都可以正常工作,但列数据中带有字符串的条件则不行。我收到该列不存在的错误。我正在使用:

df = pd.read_sql_query('SELECT "variable1", "variable2" FROM "Table1" WHERE "variable1" = 123 AND "variable2" = "abc" ', engine)

我认为我使用“abc”而不是“abc”可能是一个问题,但由于查询参数中的 ' 符号,我无法更改它。如果我将那些 ' 更改为 " 则无法正确检测到列名和表名(因为之前的问题它们必须用引号引起来)。

这是错误信息:

ProgrammingError: (psycopg2.errors.UndefinedColumn) ERROR:  COLUMN »abc« does not exist
LINE 1: ...er" FROM "Table1" WHERE "variable2" = "abc"
And there is an arrow pointing to the first quotation mark of the "abc".

我是 SQL 新手,如果有人能指出我正确的方向,我将不胜感激。

【问题讨论】:

  • 应该是:AND "variable2" = 'abc'。顺便说一句,您不能用" 引用字符串。除非非常必要,否则您不需要用双引号将表名和列括起来。恕我直言,这是一种不好的做法,只会导致混乱。这也有效:SELECT variable1, variable2 FROM Table1 WHERE variable1 = 123 AND variable2 = 'abc'
  • 我猜这就是问题所在。但是,当我使用“abc”时,引号会取消参数中的引号,并且会出现语法错误。当我不对表和列使用双引号时,它不起作用 - “列不存在”。也许是我奇怪地创造了它们。
  • 你不能用" 包装整个sql 语句,例如"SELECT variable1, variable2 FROM Table1 WHERE variable1 = 123 AND variable2 = 'abc'"?
  • 然后取消表和列名的双引号。如果我把它们排除在外,我会得到“列不存在”错误。我认为这与我如何创建表格有关?对于其他表,我不需要双引号
  • 是的,这可能是问题所在!您是否创建了这样的表create table "table1" (...?我真的不鼓励对数据库对象使用双引号。它真的很讨厌,您可能会浪费很多时间来查找问题。

标签: python sql pandas postgresql sqlalchemy


【解决方案1】:

“大多数”SQL 方言(值得注意的例外是 MS SQL Server 和 MS Access)严格区分

  • 单引号:用于字符串文字,例如,WHERE thing = 'foo'
  • 双引号:用于对象(表、列)名称,例如,WHERE "some col" = 123

PostgreSQL 会抛出一个额外的问题,即如果表/列名称没有(双)引号,然后使用区分大小写的匹配,则表/列名称将被强制小写,因此如果您的表命名为 Table1,那么

  • SELECT * FROM Table1 会失败,因为 PostgreSQL 会寻找 table1,但是
  • SELECT * FROM "Table1" 会成功。

避免查询混淆的方法是使用查询参数而不是字符串文字:

# set up test environment
with engine.begin() as conn:
    conn.exec_driver_sql('DROP TABLE IF EXISTS "Table1"')
    conn.exec_driver_sql('CREATE TABLE "Table1" (variable1 int, variable2 varchar(50))')
df1 = pd.DataFrame([(123, "abc"), (456, "def")], columns=["variable1", "variable2"])
df1.to_sql("Table1", engine, index=False, if_exists="append")

# test .read_sql_query() with parameters
import sqlalchemy as sa
sql = sa.text('SELECT * FROM "Table1" WHERE variable1 = :v1 AND variable2 = :v2')
param_dict = {"v1": 123, "v2": "abc"}
df2 = pd.read_sql_query(sql, engine, params=param_dict)
print(df2)
"""
   variable1 variable2
0        123       abc
"""

【讨论】:

    【解决方案2】:

    应该是:AND "variable2" = 'abc'

    您不能用" 引用字符串/文字,因为 PostgreSQL 会将其解释为数据库对象。顺便提一句。您不需要用双引号将表名和列括起来,除非非常必要,例如区分大小写的对象名称、包含空格的名称等。恕我直言,这是一种不好的做法,从长远来看只会导致混乱。所以你的查询可以完美地写成如下:

    SELECT variable1, variable2 
    FROM table1 
    WHERE variable1 = 123 AND variable2 = 'abc';
    

    请记住,它也适用于其他对象,例如表或索引。

    • CREATE TABLE Table1 (id int) - 不错。
    • CREATE TABLE "Table1" (id int) - 不好。
    • CREATE TABLE "Table1" ("id" int) - 绝对不好;)

    如果您想从表名中删除不必要的双引号:

    ALTER TABLE "Table1" RENAME TO table1;
    

    演示:db<>fiddle

    【讨论】:

    • 看来我使用了替代 3 ;) 可以用一个命令删除所有引号吗?我有 50 列,不希望手动完成
    • @Elias 你不需要更改列名.. 看看我的小提琴。
    • 我认为问题在于我的列都以大写字母开头。表名也是如此。我尝试更改一些列/表名称,只要它们没有大写字母就可以了。
    • @Elias 我明白了.. 问题比我想象的要严重 :D 如果这个答案对你没有帮助,我会删除它。
    • 我知道双引号是不好的风格,但我也知道他们让我访问大写字母呵呵
    猜你喜欢
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 2018-11-24
    • 1970-01-01
    • 2023-04-03
    • 2015-05-25
    • 2013-01-18
    • 1970-01-01
    相关资源
    最近更新 更多