在 Postgres 中转义类似关键字的列名

Posted

技术标签:

【中文标题】在 Postgres 中转义类似关键字的列名【英文标题】:Escaping keyword-like column names in Postgres 【发布时间】:2011-11-30 20:57:15 【问题描述】:

如果 Postgres 表中的列名为 year,应该如何查看 INSERT 查询来设置该列的值?

例如:INSERT INTO table (id, name, year) VALUES ( ... );year 字附近出现错误。

【问题讨论】:

【参考方案1】:

为了安全起见:始终引用标识符!为此,您必须使用分隔标识符构建插入语句。

SQL 2003 指定分隔标识符应该用双引号 " 引用,如果标识符中出现双引号,则必须重复双引号。查看 BNF:

https://ronsavage.github.io/SQL/sql-2003-2.bnf.html#delimited%20identifier

这是引用标识符的 Java 代码:

static String delimited_identifier (String identifier)

  return "\"" + identifier.replaceAll ("\"", "\"\"") + "\"";

这是构建插入的代码:

static String build_insert (String table, String[] columns)

  StringBuilder sql = new StringBuilder ();
  StringBuilder values = new StringBuilder ();

  sql.append ("INSERT INTO ");
  sql.append (delimited_identifier (table));
  sql.append (" (");
  int c = 0;
  if (columns.length > 0) 
    sql.append (delimited_identifier (columns[c]));
    values.append ("?");
  
  for (++c; c < columns.length; c++) 
    sql.append (", ");
    sql.append (delimited_identifier (columns[c]));
    values.append (", ?");
  
  sql.append (") VALUES (");
  sql.append (values.toString ());
  sql.append (")");

  return sql.toString ();

例子:

String sql = build_insert ("Person", new String[]"First name", "Last name");

【讨论】:

@questionto42 没有必要区分两种情况。只需引用每个标识符。几乎不可能知道所有数据库的所有保留字。而且我不确定您所说的“反逗号”是什么意思。引用的正确字符是“双引号”(")。 mysql 使用反引号 (`) 违反了 SQL 标准。我的回答涵盖了正确的引用方式。 @questionto42 我不确定我是否理解。你想要我将评论移到答案中吗? 如果有类似“无需区分两种情况。只需引用每个标识符。几乎不可能知道所有数据库的所有保留字的介绍。我会更好地理解您的答案。 " 在这个问题上扔Java代码不仅没用,还很可怕……【参考方案2】:

如果您没有在任何字段/列中提供引号,则默认情况下 Postgres 将其小写。 Postgres 会在涉及到列名时跳过检查关键字。

在您的情况下,我认为在 columns 中添加引号不是强制性的。 但是如果你使用keywords(由Postgres注册)作为TableSchemaFunctionTrigger等的名称,你必须使用双引号,或者你可以指定模式名称点连接。

假设,order 是 Postgres 注册的关键字。并且在某些情况下,您必须使用此关键字作为表名。

届时,Postgres 将允许您使用keywords 创建一个表。这就是 Postgres 的美妙之处。

要访问订单表,您必须使用双引号,或者您可以在表名之前使用架构名称。

例如

1.

select * from schema_name.order;

2.

select * from "order";

同样,您可以使用这种类型的组合。希望这会对你有所帮助。

【讨论】:

【参考方案3】:

只需将year 括在双引号中即可避免将其解释为keyword:

INSERT INTO table (id, name, "year") VALUES ( ... );

来自documentation:

还有第二种标识符:分隔标识符或 带引号的标识符。它是由一个任意序列组成的 双引号 (") 中的字符。分隔标识符始终是 标识符,绝不是关键字。所以“select”可以用来指代一个 名为“select”的列或表,而未引用的选择将是 作为关键字,因此会在以下情况下引发解析错误 在需要表名或列名的地方使用。

【讨论】:

一些警告:如果没有引号,PostgreSQL 会将所有标识符折叠为小写。 MyTablemyTablemytable 是一样的。 使用 引号,此折叠未完成。所以"MyTable"mytable 不再相同。 更好的是,避免使用reserved words 或混合大小写作为标识符,您将永远不必使用双引号或收到奇怪的错误消息。 @djjeck: ***.com/questions/1992314/… @ErwinBrandstetter 问题是当你在一个已建立的项目上工作时。 @HoàngLong 是的。 update "user" set "password" = 'value...'; 工作得很好......

以上是关于在 Postgres 中转义类似关键字的列名的主要内容,如果未能解决你的问题,请参考以下文章

在 PostgreSQL 查询中转义列名中的字符?

如何在 Pyspark 的动态列列表中转义列名

在剃刀视图引擎中转义@字符

如何在 REGEXP 中转义 MySQL 中的星号 (*)

在 YAML 中转义冒号

在数据库查询字符串中转义引号的好方法?