PLpgSQL function to find columns with only NULL values in a given table

后端 未结 1 1047
生来不讨喜
生来不讨喜 2021-01-29 15:30

We have to find columns of a table with only NULL values. We are trying to build a plpgsql function that takes a table\'s name and returns the list of such columns.

How

1条回答
  •  终归单人心
    2021-01-29 16:16

    You can query the catalog table pg_attribute to get a list of columns which are not defined NOT NULL and therefore can hold NULL values:

    SELECT quote_ident(attname) AS column_can_be_null
    FROM   pg_attribute
    WHERE  attrelid = 'tbl'::regclass -- valid, visible table name 
    AND    attnum >= 1                -- exclude tableoid & friends
    AND    NOT attisdropped           -- exclude dropped columns
    AND    NOT attnotnull             -- exclude columns defined NOT NULL!
    ORDER  BY attnum;
    

    Where tbl is your (optionally schema-qualified) table name.

    Doesn't say there are any actual NULL values in the column. You'd have to test each column. Like this:

    Full automation with plpgsql function

    CREATE OR REPLACE FUNCTION f_all_null_columns_of_tbl(_tbl regclass)
      RETURNS SETOF text AS
    $func$
    DECLARE
       _row_ct  bigint;        -- count rows in table $1
       _sql     text;          -- SQL string to test for NULL values
       _cols    text[];        -- array of candidate column names
       _nulls   bool[];        -- array of test results
    BEGIN
    
    EXECUTE 'SELECT count(*) FROM ' || _tbl
    INTO _row_ct;
    
    IF _row_ct = 0 THEN
       RAISE EXCEPTION 'Table % has no rows!', _tbl;  -- pointless for empty table
    ELSE
       RAISE NOTICE '% rows in table %.', _row_ct, _tbl; 
    END IF;
    
    SELECT INTO _sql, _cols
          'SELECT ARRAY[' || string_agg('bool_and(' || col || ' IS NULL)', ', ')
           || '] FROM ' || _tbl
        , array_agg(col)
    FROM  (
       SELECT quote_ident(attname) AS col
       FROM   pg_attribute
       WHERE  attrelid = _tbl            -- valid, visible table name 
       AND    attnum >= 1                -- exclude tableoid & friends
       AND    NOT attisdropped           -- exclude dropped columns
       AND    NOT attnotnull             -- exclude columns defined NOT NULL!
       ORDER  BY attnum
       ) sub;
    
    EXECUTE _sql INTO _nulls;
    
    FOR i IN 1 .. array_upper(_cols, 1)
    LOOP
       IF _nulls[i] THEN                 -- column is NULL in all rows
          RETURN NEXT _cols[i];
       END IF;
    END LOOP;
    
    RETURN;
    END
    $func$ LANGUAGE plpgsql;
    

    Call:

    SELECT f_all_null_columns_of_tbl('my_schema.my_table');
    

    Tested with Postgres 9.1 and 9.3.
    This uses a number of advanced plpgsql features.

    SQL Fiddle.

    Related answer building SQL code and executing it, with modern syntax:

    • Replace empty strings with null values

    About traversing a record:

    • Loop through columns of RECORD

    0 讨论(0)
提交回复
热议问题