背景
shell 腳本跑 Python 寫數據腳本任務的時候報錯:
File "./xxx.py", line 59, in xxx
cur.execute(insert_sql(col_string, str(data_list)))
psycopg2.ProgrammingError: column "it’s adj for sb和it's adj of sb的區別" does not exist
LINE 1: ...1', 'student', 16, '八年級下冊', 20211028, 50347, "it’s adj ...
原因
做 print 輸出之后發現是這個數寫入報錯:
it’s adj for sb和it's adj of sb的區別
可以看出其實是 ’
和 '
混用了(作為寫作遵循互聯網寫作規范的強迫症患者我對於這種混用真的不能忍)。
然后在 stackoverflow 上查到了這個相關問題:Insert text with single quotes in PostgreSQL。但是它的解決方案在我看來還是不太符合我的要求,畢竟寫入 pg 的數據不能因為 '
報錯就強制將單個 '
轉為 ''
。所以我就將 '
替換為 ’
,發現執行還是報錯,意識到關鍵問題不在這里。
然后在 這篇博客 找到了原因,據 wiki.postgresql 官網 解釋:
PostgreSQL uses only single quotes for this (i.e. WHERE name = 'John'). Double quotes are used to quote system identifiers; field names, table names, etc. (i.e. WHERE "last name" = 'Smith').
MySQL uses ` (accent mark or backtick) to quote system identifiers, which is decidedly non-standard.
翻譯過來就是:
PostgreSQL 只能用單引號(’)表示值,雙引號(")是表示系統標識符的,比如表名或者字段名。MySQL 使用 `(重音標記或反引號)來引用系統標識符,這絕對是非標准的。
因為其實上面寫入的數據完整格式是:
insert into xxx (字段1, 字段2, 字段3) values ('student', "it’s adj for sb和it's adj of sb的區別", '概念課')
發現只有字段2外面是 "
,而 pg 的雙引號 "
是表示系統標識符,根本寫不進 pg。其實我猜測應該就是因為字符串內部有 '
,導致的外部引號變為了 "
。
於是我就在 Python 代碼里進行了字符替換:
str.replace("\"", "\'").replace("\'s ", "’s ")
先將外部 "
替換為 '
,然后再將 '
替換為 ’
。但要注意實際情況中 's
有可能會匹配到 'student'
,因此我多匹配了一位空格,將 's空
替換為 ’s空
。
感想
發現這個報錯很明顯是歷史遺留問題,但是基本不會考慮到。因為寫入 pg 數據庫的數據應該是用戶在前端輸入的,符號混用這種情況真的沒辦法去控制。然而單引號、雙引號、反引號這種在 PostgreSQL 里又和 MySQL 不太一樣,很容易引起問題。