Postgres获取所有没有空值的列

时间:2019-12-23 17:04:07

标签: python pandas postgresql

所以我有一个包含许多列和行的表,我需要对其进行过滤,以便删除具有空值的列。

在python中,我可以这样做(小示例):


df = pd.DataFrame({'col1': [1, None,3], 'col2': [3, 4,5],'col3': [3, 4,None]})

df.dropna(axis=1,how='any')

但是我只是不知道如何在postgres中做到这一点。

我找不到该问题的答案。 我确实找到了一些答案,但是它们使用的列名是我无法使用的,因为我有太多列名。

谢谢!

3 个答案:

答案 0 :(得分:2)

我不能断言它会打破任何速度记录,但是它将满足您的要求。无需动态SQL或用户定义的函数。

SELECT t.*
FROM your_table as t
-- If nulls are present, these will not be equal
WHERE to_jsonb(t) = jsonb_strip_nulls(to_jsonb(t))

如果性能成为真正的问题(例如必须多次运行此查询),则可以create an expression index。但是,如果是这种情况,我建议对数据库的数据模型进行规范化。您可能只是对结构缺陷进行书面记录。

CREATE INDEX nulls_detected
  ON your_table (to_jsonb(your_table) = jsonb_strip_nulls(to_jsonb(your_table)));

可能使用bloom filter为您的索引找到进一步的优化方法。


这是一个实际的例子:

CREATE TABLE null_example (
  id serial PRIMARY KEY,
  col1 int,
  col2 text,
  col3 boolean
);

INSERT INTO null_example (col1, col2, col3) VALUES
(1, 'test1', true),
(NULL, 'test2', false),
(3, NULL, true),
(4, 'test4', NULL),
(5, 'test5', false);

现在,如果您运行以下命令……

SELECT t.*
FROM null_example AS t
WHERE to_jsonb(t) = jsonb_strip_nulls(to_jsonb(t));

…您将获得以下输出。任何包含NULL列值的行都将被省略。

id | col1 | col2  | col3
---+------+-------+------
1  | 1    | test1 | t
5  | 5    | test5 | f

如果您尝试定位要删除的列(例如,从ALTER TABLE … DROP COLUMN语句中删除),则以下查询也可以为您提供帮助。

SELECT results.key, count(*), array_agg(t.id) AS affected_ids
FROM null_example AS t
  CROSS JOIN LATERAL jsonb_each(to_jsonb(t)) AS results(key, value)
WHERE results.value = 'null'::jsonb
GROUP BY results.key

这将返回:

 key | count | affected_ids
-----+-------+--------------
col2 | 1     | {3}
col3 | 1     | {4}
col1 | 1     | {2}

答案 1 :(得分:1)

Postgres中没有执行此操作的工具,因此您必须构建自己的函数。一种解决方法是使用以下方法检索所有列名称:

select attname
  from pg_attribute
 where attrelid = (select oid from pg_class where relname = 'foo')
   and attnum > 0;

然后循环遍历attname并执行:

select count(*)
  from foo
 where <attname> is null;

可能的功能可能看起来像

postgres=# create table foo (col1 int, col2 int, col3 int);
CREATE TABLE
postgres=# insert into foo values (1, null, null);
INSERT 0 1
postgres=# insert into foo values (1, 1, null);   
INSERT 0 1
postgres=# insert into foo values (1, null, 1);
INSERT 0 1
postgres=# CREATE OR REPLACE function find_null_cols() RETURNS setof record
AS
$$
declare
rr record;
r record;
c int;
begin
for r in (select attname
  from pg_attribute
 where attrelid = (select oid from pg_class where relname = 'foo')
   and attnum > 0)
loop
  execute format ('select count(*) from foo where %s is null', r.attname) into c;
  if c > 0 then
    select r.attname::text, c into rr;
    return next rr;
  end if;

end loop;
return;
end
$$
LANGUAGE plpgsql;
CREATE FUNCTION
postgres=# select * from find_null_cols() as x(colname text, nullcount_rows int);
 colname | nullcount_rows 
---------+----------------
 col2    |              2
 col3    |              2
(2 rows)

为了您的安全起见,我不会添加DROP COLUMN命令;)

答案 2 :(得分:0)

PostgreSQL中的动态SQL

您可以使用“ 执行语句”。 使用

获取列的名称
SELECT *
   FROM information_schema.columns
  WHERE table_schema = 'your_schema'
    AND table_name = 'your_table'
      ;

对于每个列,如果该列具有任何空值,请在视图中声明“删除”

DECLARE
    column_name text;
BEGIN
    FOR column_name IN SELECT FROM information_schema.columns WHERE table_schema = 'your_schema' AND table_name = 'your_table' LOOP

        ...
        EXECUTE 'delete from ... where(SELECT ....' || column_name || '.....)';
        ...

    END LOOP;
END;