为什么PostgreSQL不喜欢大写表名?

53

我最近尝试在PostgreSQL中创建一些全部使用大写字母命名的表。但是,为了查询它们,我需要把表名放在引号“TABLE_NAME”之内。是否有任何方法可以避免这种情况,并告诉Postgres正常处理大写字母名称?

更新

此查询创建一个小写的表table_name

create table TABLE_NAME 
(
id integer,
name varchar(255)
)

然而,这个查询创建了一个大写名字为"TABLE_NAME"的表

create table "TABLE_NAME"
(
id integer,
name varchar(255)
)

问题在于引号现在是名称的一部分!! 在我的情况下,我不是手动创建表,另一个应用程序创建表,名称均为大写字母。这会导致使用Geoserver通过CQL过滤器时出现问题。


请展示您的“CREATE TABLE”语句。 - Tim Biegeleisen
1
https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS - user330315
2
在以下链接中有一个带解释的非常好的答案: https://dev59.com/wG015IYBdhLWcg3w7wMW 希望能对你有所帮助。 - bgroper
3个回答

67
如果您想让Postgres保留关系名称的大小写,请将表名放入双引号中引用。引用标识符也使其区分大小写,而未引用的名称始终折叠为小写。例如,PostgreSQL认为标识符FOO、foo和"foo"是相同的,但"Foo"和"FOO"与这三个标识符及彼此不同。(在PostgreSQL中将未引用的名称折叠为小写与SQL标准不兼容,该标准规定未引用的名称应折叠为大写。因此,根据标准,foo应等同于"FOO"而不是"foo"。如果您想编写可移植的应用程序,则建议始终引用特定名称或从不引用它。)以上内容摘自文档(重点是我的)。以下是引用示例:
t=# create table "UC_TNAME" (i int);
CREATE TABLE
t=# \dt+ UC

t=# \dt+ "UC_TNAME"
                      List of relations
 Schema |   Name   | Type  |  Owner   |  Size   | Description
--------+----------+-------+----------+---------+-------------
 public | UC_TNAME | table | postgres | 0 bytes |
(1 row)

没有引用的示例:

t=# create table UC_TNAME (i int);
CREATE TABLE
t=# \dt+ UC_TNAME
                      List of relations
 Schema |   Name   | Type  |  Owner   |  Size   | Description
--------+----------+-------+----------+---------+-------------
 public | uc_tname | table | postgres | 0 bytes |
(1 row)

因此,如果您创建了带引号的表格,则在查询时不应该跳过引号。但是,如果您在创建对象时跳过了引号,则名称会折叠为小写,并且在查询中使用大写名称也将变成小写 - 这样您就“不会注意到”它。


你没有完全解释清楚。所以当他使用大写字母创建时,它被保留了下来,但是当他使用大写字母查询时,它变成了小写字母并且无法工作。是这样吗? - Tim Biegeleisen
我引用了文档 - 它们说“建议您始终引用特定名称或永不引用它。” 我认为这意味着“当您创建表时,无论大小写如何,都可以无需使用引号选择它。如果您的创建中包含引号,则在查询时使用引号”。 或者您有其他不同的意思吗? - Vao Tsun
但是,根据这个逻辑,OP不应该能够使用大写或小写访问他的表吗?我想他一定是用引号创建了这个表,对吧? - Tim Biegeleisen
"他应该可以访问,但不喜欢需要在表名周围加引号的事实,并询问是否可以跳过引号,只使用大写字母。" - Vao Tsun
哇,我喜欢这个网站。我终于可以睡觉了哈哈。谢谢! - James Trenda
有趣的是,您可以在不使用引号的情况下使用大写umlauts,例如Ü、Ä、Ö。 - lassej

17
这个问题意味着双引号在强制PostgreSQL识别标识符名称大小写时实际上成为标识符名称的一部分。这是不正确的。实际发生的是,如果您使用双引号来强制使用大小写,则必须始终使用双引号引用该标识符。
背景:在PostgreSQL中,标识符名称总是折叠为小写,除非您用双引号括住标识符名称。这可能会导致混淆。
考虑按顺序运行以下两个语句会发生什么:
CREATE TABLE my_table (
    t_id serial,
    some_value text
);

这将创建一个名为my_table的表格。

现在,尝试运行以下内容:

CREATE TABLE My_Table (
    t_id serial,
    some_value text
);

PostgreSQL忽略了大写(因为表名没有被引号包围),并试图创建另一个名为my_table的表。当这种情况发生时,它会抛出一个错误:

PostgreSQL 忽略了大小写(因为表名没有被引号包围),并尝试创建名为 my_table 的另一张表。当发生这种情况时,它会抛出一个错误:

ERROR:  relation "my_table" already exists

要创建一个由大写字母组成的表格,您需要运行以下命令:

要创建一个由大写字母组成的表格,您需要运行以下命令:

CREATE TABLE "My_Table" (
    t_id serial,
    some_value text
);

现在您的数据库中有两个表:

 Schema |           Name            | Type  |  Owner   
--------+---------------------------+-------+----------
 public | My_Table                  | table | postgres
 public | my_table                  | table | postgres

唯一访问 My_Table 的方法是用双引号括起标识符名称,例如:

SELECT * FROM "My_Table"

如果您将标识符不加引号地离开,则PostgreSQL会将其折叠为小写并查询my_table


5

简单来说,Postgres将带有双引号""的数据视为区分大小写,其余则视为小写。

例如:我们可以创建两个名为DETAILS和details的列,在查询时:

select "DETAILS" 

返回 DETAILS 列的数据并且

select details/DETAILS/Details/"details"

返回详细列数据。

这基本上意味着Postgres中的所有查询默认都会转换为小写字母。但是, 如果您想创建一个带有大写字母的列,则必须在“”内指定它。并且要获取大写列(DETAILS)的数据,您需要在(双引号)“”中指定列名。这样Postgres就会将引号中的数据视为区分大小写,并提供预期的列(DETAILS)值。 - Teja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接