【问题标题】:SQL to return list of fields containing non-NULL dataSQL 返回包含非 NULL 数据的字段列表
【发布时间】:2011-10-17 08:47:39
【问题描述】:

如何从给定表中返回包含任何非 NULL 数据的字段列表?

作为示例,我如何查询下面的示例表以仅返回以下三个值,因为它们包含 NULL 以外的内容。

  • LO2_HiddenOrgID
  • LO2_BranchOfOrgID
  • LO2_ShortName

我希望尽可能地自动执行此操作,因为我有几千个字段要检查。

另外,我目前在开发时使用 SQLite,但我很乐意接受任何特定于 SQLite、MySQL 或 PostgreSQL 的建议。

【问题讨论】:

  • 所以查询应该返回找到数据的列的列表,而不是数据本身?
  • 我认为如果你只想输出具有值的列,应该在编程代码上完成。
  • @nineside 是的。我正在尝试建立一个要保留的字段列表。此时任何只有 NULL 数据的字段都可以被清除。这些数据是无关紧要的,因为它稍后会被移植回来。

标签: mysql sql sqlite postgresql


【解决方案1】:

所以您的目标是获取列名列表,这样所有列名中的任何行中都至少有一个非 NULL 值,对吧?如果是这样,请参见下文...

您无法对 SQL 查询中的列名称进行参数化,因此您需要以您选择的客户端语言动态构建 SQL 文本。算法如下所示:

  1. 您必须提前知道列名列表。有一些方法可以在 PostgreSQLMySQL 和大多数其他数据库中自动检索此列表。
  2. 遍历此列表并为每个 column_name 动态构建 SQL 文本,例如:SELECT column_name FROM YOUR_TABLE WHERE column_name IS NOT NULL LIMIT 1(请参阅 MySQL LIMIT 和 PostgreSQL LIMIT)。
  3. 执行上面的查询并获取结果。如果其中有一行,请将column_name 添加到结果列表
  4. 在列名列表中有元素时继续迭代。

结果列表现在包含具有至少一个非 NULL 值的列。

【讨论】:

  • 您还可以使用查询系统目录的存储过程,这是一个更好的解决方案。您不必提前知道任何事情。
【解决方案2】:

完全自动化的 PostgreSQL 完整解决方案

返回所有模式中的所有(非系统)表,其中所有列至少具有一个非空值。
您必须是超级用户(如 postgres)才能调用此函数。
或者你是一个超级用户可以拥有这个函数,它是用SECURITY DEFINER创建的。

CREATE OR REPLACE FUNCTION f_tbl_with_nonull_cols()
  RETURNS TABLE(tbl text, columns text) AS
$BODY$
DECLARE
    rel_id  oid;        -- oid of table
    sch     text;       -- schema name
    cols1   text;       -- columns defined NOT NULL
    cols2   text;       -- other columns
    q       text;       -- for query string
    has_row bool;       -- table has rows?
BEGIN

FOR rel_id, sch, tbl IN
SELECT c.oid            -- AS rel_id
      ,n.nspname        -- as sch
      ,c.relname        -- as tbl
FROM   pg_catalog.pg_class c
LEFT   JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE  c.relkind = 'r'
AND    n.nspname <> 'pg_catalog'
AND    n.nspname <> 'information_schema'
AND    n.nspname !~ '^pg_toast'
AND    pg_catalog.pg_table_is_visible(c.oid)
ORDER  BY 2,3

LOOP
    EXECUTE 'SELECT EXISTS (SELECT 1 FROM '
             || quote_ident(sch) ||'.' || quote_ident(tbl) || ')'
    INTO has_row;

    IF has_row THEN
        -- defined NOT NULL -> must have values.
        SELECT INTO cols1
               string_agg(a.attname,', ')
        FROM   pg_catalog.pg_attribute a
        WHERE  a.attrelid = rel_id
        AND    a.attnum > 0
        AND    NOT a.attisdropped
        AND    a.attnotnull;

        SELECT INTO q
               'array_to_string(ARRAY['
                || string_agg('CASE WHEN count(' || quote_ident(a.attname)
                || ') > 0 THEN '''|| a.attname || ''' ELSE NULL END', ', ')
                || '], '', '')'
        FROM   pg_catalog.pg_attribute a
        WHERE  a.attrelid = rel_id
        AND    a.attnum > 0
        AND    NOT a.attisdropped
        AND    NOT a.attnotnull;

        IF q IS NOT NULL THEN
            EXECUTE 'SELECT ' || q || '
            FROM  ' || quote_ident(sch) || '.' || quote_ident(tbl)
            INTO cols2;

            columns := COALESCE(cols1 || ', ', '') || cols2;
        ELSE
            columns := COALESCE(cols1, '');
        END IF;

        RETURN NEXT;
    ELSE
        -- no rows, so no columns with non-null values
    END IF;
END LOOP;

呼叫:

SELECT * FROM f_tbl_with_nonull_cols();
       tbl      |                   columns
----------------+----------------------------------
 table1         | id, col1, col7,
 table2         | id, col4, col5, col8, col9, col10
 table5         | some_id
...

【讨论】:

    【解决方案3】:

    @citricguy:我相信您需要所有包含非空数据的列,而无需专门选择查询中的任何列。如果不是,请纠正我。

    【讨论】:

    • 就是这样。但是他怎么知道这一列是否没有任何价值?
    • 我真的只需要列名。我更喜欢包含我想的数据的列列表,但我总是可以轻松地反转列表。数据无关紧要,因为它稍后会被移植回新的、干净的数据库中。
    【解决方案4】:
    SELECT LO2_HiddenOrgID FROM MyTable WHERE LO2_HiddenOrgID IS NOT NULL 
    UNION ALL
    SELECT LO2_BranchOfOrgID FROM MyTable WHERE LO2_BranchOfOrgID IS NOT NULL 
    

    等等

    【讨论】:

    • 我相信他在寻找列名,而不是数据
    • 两个查询是一样的。他正在寻找仅输出不具有空值的列的脚本。
    • @Bryan 你认为它想要这个?
    【解决方案5】:

    @xanatos 说了什么,但在所选列名周围加上引号..

    SELECT distinct 'LO2_HiddenOrgID' FROM MyTable WHERE LO2_HiddenOrgID IS NOT NULL 
    UNION ALL
    SELECT distinct 'LO2_BranchOfOrgID' FROM MyTable WHERE LO2_BranchOfOrgID IS NOT NULL 
    UNION ALL
    SELECT distinct 'LO2_HiddenOtyID' FROM MyTable WHERE LO2_HiddenOtyID IS NOT NULL 
    UNION ALL
    SELECT distinct 'LO2_ShortName' FROM MyTable WHERE LO2_ShortName IS NOT NULL 
    

    【讨论】:

      【解决方案6】:

      这并不能完全回答您的问题,但此查询将返回每列中非空项目的数量。如果您检查返回的值,您可以输出这些字段。

      SELECT COUNT(Col1) AS Col1, COUNT(Col2) AS Col2, COUNT(Col3) ASCol3, 等....
      FROM table
      WHERE table.Col1 IS NOT NULL OR table.Col2 IS NOT NULL OR table.Col3 IS NOT NULL 等..

      【讨论】:

        【解决方案7】:

        在 SQLite 中,我会选择这样的东西,你可以在功能更丰富的 RDBMS 中做一些聪明的事情:

        SELECT 'LO2_HiddenOrgID'
        FROM MyTable
        WHERE LO2_HiddenOrgID IS NOT NULL
        LIMIT 1
        UNION
        SELECT 'LO2_BranchOfOrgID'
        FROM MyTable
        WHERE LO2_BranchOfOrgID IS NOT NULL
        LIMIT 1
        UNION
        SELECT 'LO2_HiddenOtyID'
        FROM MyTable
        WHERE LO2_HiddenOtyID IS NOT NULL
        LIMIT 1
        

        应该可以根据存储在 SQLite 数据字典中的元数据动态生成上述查询:

        SELECT * 
        FROM sqlite_master
        WHERE tbl_name = 'MyTable' 
        AND type = 'table'
        

        【讨论】:

          猜你喜欢
          • 2016-04-11
          • 2011-11-01
          • 1970-01-01
          • 2017-11-02
          • 2016-10-29
          • 1970-01-01
          • 2013-03-22
          • 2020-10-02
          • 1970-01-01
          相关资源
          最近更新 更多