Postgresql
將 hstore 條目添加到未初始化 (NULL) 列
我最近被這個“功能”咬了。
如果您的
hstore
列未初始化並且您開始向其中添加條目,它們都會被無聲地吞噬而不會出錯。這是預期的嗎?
create table test_hstore(id int, map hstore); insert into test_hstore(id,map) values(0, ''); INSERT 0 1 select * from test_hstore ; id | map ----+----- 0 | update test_hstore set map = map || hstore('key1', 'value1') where id = 0; UPDATE 1 select * from test_hstore; id | map ----+------------------ 0 | "key1"=>"value1" update test_hstore set map = null where id = 0; UPDATE 1 select * from test_hstore; id | map ----+-------- 0 | (null) update test_hstore set map = map || hstore('key1', 'value1') where id = 0; UPDATE 1 select * from test_hstore; id | map ----+-------- 0 | (null)
如果我不能對列有非空約束,我可以通過做類似的事情來保護自己(這實際上不起作用):
UPDATE test_hstore SET map = (IF map IS NULL THEN '' || hstore('key1', 'value1') ELSE map || hstore('key1', 'value1')) WHERE id = 0;
在 SQL 中,
NULL (operator) (value)
一般是NULL
.這不是 hstore 獨有的,而是一切的規範。
空字元串
''
不同於 NULL。'' || 'somestring'
是'somestring'
,NULL || 'somestring'
而是NULL
。對於
hstore
. 就像NULL + 1
是NULL
。如果這對您來說是個問題,您可能應該儲存空
hstore
值,而不是在列上NULL
分配一個約束。NOT NULL
@Craig 提供了詳細的解釋和避免該問題的最佳建議:定義列
NOT NULL DEFAULT ''
- 將每行 1 個字節添加到儲存(通常)列可以NULL
代替的位置。手頭問題的簡單標準解決方案
COALESCE()
- 與任何其他可能的數據類型一樣NULL
。允許NULL
列中的值是完全合理的設計,您只需要正確處理它即可。你的想法
IF
很接近,但這不是 SQL 語言的一部分(在標準 SQL 和 Postgres 中都沒有)。其他一些 RDBMS(如 MySQL )將IF
和引入IFNULL
SQL,但這些RDBMS 並沒有增加標準功能CASE
和COALESCE
.CREATE TEMP TABLE test_hstore AS SELECT '1'::int AS id, NULL::hstore AS map; -- test table with 1 row UPDATE test_hstore SET map = map || hstore('key1', 'value1') RETURNING *; 編號 | 地圖 ----+-------- 1 | (空值) UPDATE test_hstore SET map = **COALESCE(map, '')** || hstore('key1', 'value1') RETURNING *; 編號 | 地圖 ----+------------------ 1 | “鍵1”=>“值1”
db<>fiddle here