【问题标题】:ProgrammingError: (psycopg2.errors.UndefinedColumn), while working with sqlalchemyProgrammingError: (psycopg2.errors.UndefinedColumn),在使用 sqlalchemy 时
【发布时间】:2020-07-16 00:46:45
【问题描述】:

我无法查询在 postgres db(本地)上使用 sqlalchemy 创建的表。

虽然我能够执行并接收查询结果:

SELECT * FROM olympic_games 

当我尝试访问单个列或对表执行任何其他操作时收到错误消息:

SELECT games FROM olympic_games

错误信息是(从波兰语翻译过来的几句话):

ProgrammingError: (psycopg2.errors.UndefinedColumn) BŁĄD: 列“游戏”不存在

第 1 行:选择 COUNT(运动)
^
提示:也许你的意思是“olympic_games.Games”。

SQL:从 olympic_games LIMIT 5 中选择游戏;]
(此错误的背景:http://sqlalche.me/e/f405

这几乎可以概括为该程序看不到,或者可以访问特定列,并显示它不存在。

我尝试使用table.column 格式访问,但效果不佳。我还可以通过information_schema.columns 看到列名

数据 (.csv) 使用 pd.read_csv 加载,然后是 DataFrame.to_sql。代码如下,感谢帮助!

engine = create_engine('postgresql://:@:/olympic_games')

with open('olympic_athletes_2016_14.csv', 'r') as file:
    df = pd.read_csv(file, index_col='ID')
df.to_sql(name = 'olympic_games', con = engine, if_exists = 'replace', index_label = 'ID')

两个执行命令都返回相同的错误:

with engine.connect() as con:
    rs = con.execute("SELECT games FROM olympic_games LIMIT 5;")
    df_fetch = pd.DataFrame(rs.fetchall())
df_fetch2 = engine.execute("""SELECT games FROM olympic_games LIMIT 5;""").fetchall()

【问题讨论】:

    标签: python sql postgresql sqlalchemy


    【解决方案1】:

    本质上,这是 PostgreSQL manual 中提到的列标识符的双引号问题:

    引用标识符也使其区分大小写,而未引用的名称总是折叠为小写。例如,标识符 FOO、foo 和“foo”在 PostgreSQL 中被认为是相同的,但“Foo”和“FOO”与这三个不同并且彼此不同。

    当您的任何 Pandas 数据框列包含大小写混合时,DataFrame.to_sql 通过在 CREATE TABLE 阶段创建带双引号的列来保持区分大小写。具体来说,使用 replace

    时的以下 Python Pandas 代码
    df.to_sql(name='olympic_games', con=engine, if_exists='replace', index_label='ID')
    

    如果 Sport 是数据框中的标题案例列,则在 Postgres 中转换如下:

    DROP TABLE IF EXISTS public."olympic_games";
    
    CREATE TABLE public."olympic_games"
    (
        ...
        "Sport" varchar(255)
        "Games" varchar(255)
        ...
    );
    

    一旦标识符被混合大小写引用,它必须始终以这种方式引用。因此sport"Sport" 不同。请记住,在 SQL 中,双引号实际上不同于在 Python 中可以互换的单引号。

    要解决此问题,请考虑将所有 Pandas 列呈现为小写,因为 "games"gamesGamesGAMES 相同(但不是 "Games""GAMES")。

    df.columns = df.columns.str.lower()
    df.to_sql(name='olympic_games', con=engine, if_exists='replace', index_label='ID')
    

    或者,保持原样并适当引用:

    SELECT "Games" FROM olympic_games
    

    【讨论】:

    • 非常感谢您的帮助,小写帮助:)
    【解决方案2】:

    试试SELECT "games" FROM olympic_games。在某些情况下,PostgreSQL 在列名周围创建引号。例如,如果列名包含混合寄存器。我必须提醒你:PostgreSQL 是区分大小写的

    【讨论】:

    • PostgreSQL 不区分大小写,除非使用带引号的标识符,并且它不会在标识符周围创建引号,除非您明确使用它们。 ASDFasdfAsDf,但它们都不是 "ASDF"。 Iirc PostgreSQL 与 Oracle 的不同之处在于后者将普通标识符折叠为大写,因此所有呈现的标识符都将匹配 Oracle 中的 "ASDF"
    • 哦,对不起。我错过了一些东西。谢谢你的解释。
    猜你喜欢
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-09
    • 2015-02-27
    相关资源
    最近更新 更多