在整个数据库中将空字符串('')设置为 NULL
Set empty strings ('') to NULL in the whole database
在我的数据库中有许多值为空字符串的文本列 (''
)。空字符串需要设置为 NULL
。我不知道这个数据库中的确切模式、表和列,或者我想编写一个可以重复使用的通用解决方案。
我将如何编写查询/函数来查找所有模式中所有表中的所有文本列并将所有包含空字符串 (''
) 的列更新为 NULL
?
最简单的方法是手动,table table。对于每个 table,做这样的事情:
START TRANSACTION;
UPDATE tablename SET
stringfield1 = NULLIF(stringfield1, ''),
stringfield2 = NULLIF(stringfield2, '');
<do some selects to make sure everything looks right>
COMMIT;
这将重写 table 中的每一行,但它只会在 table 上传递一次。这对您来说可能不切实际。
您可能希望使用 WHERE
子句逐个字段执行此操作,以减少更新次数,就像这样。
START TRANSACTION;
UPDATE tablename SET stringfield1 = NULL WHERE stringfield1 = '';
<do some selects to make sure everything looks right>
COMMIT;
这只会重写需要重写的行,但每个 table 都需要多次传递。
实现此目的的最有效方法:
- 运行 每个 table.
一个 UPDATE
- 仅使用任何实际的空字符串更新可为空的列(未定义
NOT NULL
)。
- 仅更新包含任何实际空字符串的行。
- 保持其他值不变。
这个相关的答案有一个 plpgsql 函数,它使用系统目录 pg_attribute
为任何给定的 table:
自动安全地构建和运行 UPDATE
命令
- Replace empty strings with null values
使用此答案中的函数 f_empty2null()
,您可以像这样遍历选定的 tables:
DO
$do$
DECLARE
_tbl regclass;
BEGIN
FOR _tbl IN
SELECT c.oid::regclass
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r' -- only regular tables
AND n.nspname NOT LIKE 'pg_%' -- exclude system schemas
LOOP
RAISE NOTICE $$PERFORM f_empty2null('%');$$, _tbl;
-- PERFORM f_empty2null(_tbl); -- uncomment to prime the bomb
END LOOP;
END
$do$;
小心! 这会更新数据库中所有用户 table 的所有列中的所有空字符串。确保这就是您想要的,否则它可能会破坏您的数据库。
当然,您需要对所有选定的 table 拥有 UPDATE
权限。
作为儿童安全装置,我评论了有效负载。
您可能已经注意到我直接使用系统目录,而不是信息模式(这也可以)。关于这个:
- How to check if a table exists in a given schema
- Query to return output column names and data types of a query, table or view
重复使用
这是一个可以重复使用的集成解决方案。没有安全装置:
CREATE OR REPLACE FUNCTION f_all_empty2null(OUT _tables int, OUT _rows int) AS
$func$
DECLARE
_typ CONSTANT regtype[] := '{text, bpchar, varchar, \"char\"}';
_sql text;
_row_ct int;
BEGIN
_tables := 0; _rows := 0;
FOR _sql IN
SELECT format('UPDATE %s SET %s WHERE %s'
, t.tbl
, string_agg(format($$%1$s = NULLIF(%1$s, '')$$, t.col), ', ')
, string_agg(t.col || $$ = ''$$, ' OR '))
FROM (
SELECT c.oid::regclass AS tbl, quote_ident(attname) AS col
FROM pg_namespace n
JOIN pg_class c ON c.relnamespace = n.oid
JOIN pg_attribute a ON a.attrelid = c.oid
WHERE n.nspname NOT LIKE 'pg_%' -- exclude system schemas
AND c.relkind = 'r' -- only regular tables
AND a.attnum >= 1 -- exclude tableoid & friends
AND NOT a.attisdropped -- exclude dropped columns
AND NOT a.attnotnull -- exclude columns defined NOT NULL!
AND a.atttypid = ANY(_typ) -- only character types
ORDER BY a.attnum
) t
GROUP BY t.tbl
LOOP
EXECUTE _sql;
GET DIAGNOSTICS _row_ct = ROW_COUNT; -- report nr. of affected rows
_tables := _tables + 1;
_rows := _rows + _row_ct;
END LOOP;
END
$func$ LANGUAGE plpgsql;
致电:
SELECT * FROM pg_temp.f_all_empty2null();
Returns:
_tables | _rows
---------+---------
23 | 123456
注意 我是如何正确转义 table 和列名的!
c.oid::regclass AS tbl, quote_ident(attname) AS col
考虑:
- Table name as a PostgreSQL function parameter
小心! 警告同上。
还要考虑我上面链接的答案中的基本解释:
- Replace empty strings with null values
我认为下面的代码是通用的。你可以随时随地使用它:
Declare @Query varchar(1000)
declare @AllDatabaseTables table(id int,Table_Name varchar(50))
Insert into @AllDatabaseTables select Table_Name from information_schema.tables
declare @Table_Name varchar(50)
declare @i int=1
While @i<=(Select Count(*) from @AllDatabaseTables)
BEGIN
Select @Table_Name=Table_Name from @AllDatabaseTables Where id=@i
Declare @ColumnTable table(id int,ColumnName varchar(100))
Insert into @ColumnTable Select COLUMN_NAME from information_schema.columns Where Table_Name=@Table_Name and DATA_TYPE='varchar' --if the datatype is varchar type
Declare @ColumnName varchar(50)
Declare @k int=1
While @k<=(Select count(*) from @ColumnTable)
BEGIN
Select @ColumnName=ColumnName from @ColumnTable where id=@k
Set @Query='Update '+@Table_Name+' Set '+@ColumnName+'=NULL where '+@ColumnName+'='''' '
Exec(Query)
Set @k=@k+1
END
Set @i=@i+1
END
在我的数据库中有许多值为空字符串的文本列 (''
)。空字符串需要设置为 NULL
。我不知道这个数据库中的确切模式、表和列,或者我想编写一个可以重复使用的通用解决方案。
我将如何编写查询/函数来查找所有模式中所有表中的所有文本列并将所有包含空字符串 (''
) 的列更新为 NULL
?
最简单的方法是手动,table table。对于每个 table,做这样的事情:
START TRANSACTION;
UPDATE tablename SET
stringfield1 = NULLIF(stringfield1, ''),
stringfield2 = NULLIF(stringfield2, '');
<do some selects to make sure everything looks right>
COMMIT;
这将重写 table 中的每一行,但它只会在 table 上传递一次。这对您来说可能不切实际。
您可能希望使用 WHERE
子句逐个字段执行此操作,以减少更新次数,就像这样。
START TRANSACTION;
UPDATE tablename SET stringfield1 = NULL WHERE stringfield1 = '';
<do some selects to make sure everything looks right>
COMMIT;
这只会重写需要重写的行,但每个 table 都需要多次传递。
实现此目的的最有效方法:
- 运行 每个 table. 一个
- 仅使用任何实际的空字符串更新可为空的列(未定义
NOT NULL
)。 - 仅更新包含任何实际空字符串的行。
- 保持其他值不变。
UPDATE
这个相关的答案有一个 plpgsql 函数,它使用系统目录 pg_attribute
为任何给定的 table:
UPDATE
命令
- Replace empty strings with null values
使用此答案中的函数 f_empty2null()
,您可以像这样遍历选定的 tables:
DO
$do$
DECLARE
_tbl regclass;
BEGIN
FOR _tbl IN
SELECT c.oid::regclass
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r' -- only regular tables
AND n.nspname NOT LIKE 'pg_%' -- exclude system schemas
LOOP
RAISE NOTICE $$PERFORM f_empty2null('%');$$, _tbl;
-- PERFORM f_empty2null(_tbl); -- uncomment to prime the bomb
END LOOP;
END
$do$;
小心! 这会更新数据库中所有用户 table 的所有列中的所有空字符串。确保这就是您想要的,否则它可能会破坏您的数据库。
当然,您需要对所有选定的 table 拥有 UPDATE
权限。
作为儿童安全装置,我评论了有效负载。
您可能已经注意到我直接使用系统目录,而不是信息模式(这也可以)。关于这个:
- How to check if a table exists in a given schema
- Query to return output column names and data types of a query, table or view
重复使用
这是一个可以重复使用的集成解决方案。没有安全装置:
CREATE OR REPLACE FUNCTION f_all_empty2null(OUT _tables int, OUT _rows int) AS
$func$
DECLARE
_typ CONSTANT regtype[] := '{text, bpchar, varchar, \"char\"}';
_sql text;
_row_ct int;
BEGIN
_tables := 0; _rows := 0;
FOR _sql IN
SELECT format('UPDATE %s SET %s WHERE %s'
, t.tbl
, string_agg(format($$%1$s = NULLIF(%1$s, '')$$, t.col), ', ')
, string_agg(t.col || $$ = ''$$, ' OR '))
FROM (
SELECT c.oid::regclass AS tbl, quote_ident(attname) AS col
FROM pg_namespace n
JOIN pg_class c ON c.relnamespace = n.oid
JOIN pg_attribute a ON a.attrelid = c.oid
WHERE n.nspname NOT LIKE 'pg_%' -- exclude system schemas
AND c.relkind = 'r' -- only regular tables
AND a.attnum >= 1 -- exclude tableoid & friends
AND NOT a.attisdropped -- exclude dropped columns
AND NOT a.attnotnull -- exclude columns defined NOT NULL!
AND a.atttypid = ANY(_typ) -- only character types
ORDER BY a.attnum
) t
GROUP BY t.tbl
LOOP
EXECUTE _sql;
GET DIAGNOSTICS _row_ct = ROW_COUNT; -- report nr. of affected rows
_tables := _tables + 1;
_rows := _rows + _row_ct;
END LOOP;
END
$func$ LANGUAGE plpgsql;
致电:
SELECT * FROM pg_temp.f_all_empty2null();
Returns:
_tables | _rows
---------+---------
23 | 123456
注意 我是如何正确转义 table 和列名的!
c.oid::regclass AS tbl, quote_ident(attname) AS col
考虑:
- Table name as a PostgreSQL function parameter
小心! 警告同上。
还要考虑我上面链接的答案中的基本解释:
- Replace empty strings with null values
我认为下面的代码是通用的。你可以随时随地使用它:
Declare @Query varchar(1000)
declare @AllDatabaseTables table(id int,Table_Name varchar(50))
Insert into @AllDatabaseTables select Table_Name from information_schema.tables
declare @Table_Name varchar(50)
declare @i int=1
While @i<=(Select Count(*) from @AllDatabaseTables)
BEGIN
Select @Table_Name=Table_Name from @AllDatabaseTables Where id=@i
Declare @ColumnTable table(id int,ColumnName varchar(100))
Insert into @ColumnTable Select COLUMN_NAME from information_schema.columns Where Table_Name=@Table_Name and DATA_TYPE='varchar' --if the datatype is varchar type
Declare @ColumnName varchar(50)
Declare @k int=1
While @k<=(Select count(*) from @ColumnTable)
BEGIN
Select @ColumnName=ColumnName from @ColumnTable where id=@k
Set @Query='Update '+@Table_Name+' Set '+@ColumnName+'=NULL where '+@ColumnName+'='''' '
Exec(Query)
Set @k=@k+1
END
Set @i=@i+1
END