带换行符的列名[英] Column names with line breaks

本文是小编为大家收集整理的关于带换行符的列名的处理方法,想解了带换行符的列名的问题怎么解决?带换行符的列名问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我知道对于PostgreSQL中的文本字符串,换行符是通过在文本前面附加符号E或e来统一的:

SELECT E'first\nsecond'

结果:

first
second

但 PostgreSQL 也支持列名中的换行符 - 不确定这种做法为什么或有多邪恶,但可以执行以下操作:

CREATE TABLE One("first\nsecond" text);
CREATE TABLE Two("first
second" text);

当您不幸遇到其中一种情况时,您会发现虽然这些查询有效:

SELECT "first\nsecond" from One;
SELECT "first
second" from Two;

这些没有:

SELECT "first
second" from One;
SELECT "first\nsecond" from Two;

我的问题是:PostgreSQL中有没有办法统一这些差异,类似于列值的情况?

我尝试将 E 放在 "first\nsecond" 列名的前面,但不支持.尝试使用 \r\n 代替(我使用的是 Windows)给了我第三种类型的列名,只能查询为:

SELECT "first\r\nsecond" FROM Third

推荐答案

列名是标识符,标识符语法的血淋淋的细节描述在:

http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS

TL;DR:使用 U&"..." 语法通过其 Unicode 代码点将不可打印字符注入标识符中,并且没有办法将 CR,LF 与 LF 单独统一.

如何在一行中引用列

我们可以在标识符中使用 Unicode 转义序列,因此根据文档,以下操作确实有效:

select U&"first\000asecond" from Two;

如果只是两个单词之间的换行符.

第一个表上的查询会发生什么

表的创建是:

CREATE TABLE One("first\nsecond" text);

由于反斜杠字符在这里没有特殊含义,因此该列不包含任何换行符.它包含 first 后跟 \ 后跟 n 后跟 second.所以:

 SELECT "first\nsecond" from One;

确实有效,因为它与 CREATE TABLE 中的内容相同

SELECT "first
second" from One;

失败,因为该 SELECT 中有一个换行符,其中表中的实际列名有一个反斜杠,后跟一个 n.

第二张表上的查询会发生什么

这与"一"相反.

CREATE TABLE Two("first
second" text);

换行符是逐字记录的,是列的一部分.所以

SELECT "first
second" from Two;

有效,因为换行符与 CREATE TABLE 中的完全相同,带有嵌入式换行符,而

SELECT "first\nsecond" from Two;

失败,因为之前的 \n 在这种情况下并不意味着换行.

回车后跟换行符,或者更奇怪的东西

正如评论和您的编辑中提到的,这可能是回车和换行,在这种情况下应该这样做:

select U&"first\000d\000asecond" from Two;

尽管在我的测试中,在 Unix 和 Windows 上用 psql 在列的中间按 Enter 具有相同的效果:列名称中只有一个换行符.

要检查列名中的确切字符,我们可以检查它们的十六进制.

当应用于您的创建表示例时,来自 Unix 下的 psql 内部:

CREATE TABLE Two("first
second" text);

select convert_to(column_name::text,'UTF-8')
 from information_schema.columns 
 where table_schema='public'
   and table_name='two';

结果是:

        convert_to         
----------------------------
 \x66697273740a7365636f6e64

对于更复杂的情况(例如 UTF-8 中具有多个字节的非 ascii 字符),更高级的查询可能会有所帮助,以获取易于阅读的代码点:

select c,lpad(to_hex(ascii(c)),4,'0') from (
  select regexp_split_to_table(column_name::text,'')  as c
    from  information_schema.columns
    where table_schema='public'
    and table_name='two'
  ) as g;

 c | lpad 
---+------
 f | 0066
 i | 0069
 r | 0072
 s | 0073
 t | 0074
  +| 000a
   | 
 s | 0073
 e | 0065
 c | 0063
 o | 006f
 n | 006e
 d | 0064

本文地址:https://www.itbaoku.cn/post/1763871.html