【问题标题】:SELECT statement to remove empty columns from resultset with variable dataSELECT 语句从具有可变数据的结果集中删除空列
【发布时间】:2021-01-28 05:48:32
【问题描述】:

我有一个从 CSV 导入的表格,作为将数据收集到其他表格的中间步骤。此表中的所有列可能为空,但只要一列有数据,就是有效行。因此,可能存在包含空数据的完整行,这是无效的考虑。 这是此类表的(简化)示例:

/* Table Structure */
CREATE TABLE `imported_data` (
  `title` varchar(45) DEFAULT NULL,
  `description` varchar(45) DEFAULT NULL,
  `language` varchar(45) DEFAULT NULL,
  `url` varchar(45) DEFAULT NULL,
  `category` varchar(45) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8

/* Table Data */
INSERT INTO imported_data (title, `description`, `language`, url, category) VALUES
('Le Titre', '', 'fra', '', '1'),
('', 'English Letters for Kids', '', 'https://anything.net', '2'),
('', '', '', '', ''),
('Master', 'The greatest master.', 'eng', 'http://www.master.com', '3'),
('', '', '', '', ''),
('', '', 'spa', '', '');


╔══════════╤══════════════════════════╤══════════╤═══════════════════════╤══════════╗
║ title    │ description              │ language │ url                   │ category ║
╠══════════╪══════════════════════════╪══════════╪═══════════════════════╪══════════╣
║          │                          │ fra      │                       │ 1        ║
╟──────────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║          │ English letters for Kids │          │ https://anything.net  │ 2        ║
╟──────────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║          │                          │          │                       │          ║
╟──────────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║          │ The greatest master.     │ eng      │ http://www.master.com │ 3        ║
╟──────────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║          │                          │          │                       │          ║
╟──────────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║          │                          │ spa      │                       │          ║
╚══════════╧══════════════════════════╧══════════╧═══════════════════════╧══════════╝

注意:请注意上述表格/数据来自外部来源,不可修改,也没有主键。它只是在 MySQL 中导入。我不会得到NULL 值,因为所有列都是VARCHAR

我使用以下 SELECT 语句来获取同一张表,但以这种方式没有完整的空行:

SELECT title, `description`, `language`, url, category
FROM imported_data2 WHERE
title != ''  OR `description` != ''  OR `language` != ''  OR url != ''  OR category != '' 

╔═══════╤══════════════════════════╤══════════╤═══════════════════════╤══════════╗
║ title │ description              │ language │ url                   │ category ║
╠═══════╪══════════════════════════╪══════════╪═══════════════════════╪══════════╣
║       │                          │ fra      │                       │ 1        ║
╟───────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║       │ English letters for Kids │          │ https://anything.net  │ 2        ║
╟───────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║       │ The greatest master.     │ eng      │ http://www.master.com │ 3        ║
╟───────┼──────────────────────────┼──────────┼───────────────────────┼──────────╢
║       │                          │ spa      │                       │          ║
╚═══════╧══════════════════════════╧══════════╧═══════════════════════╧══════════╝

我需要怎么做才能删除行全部为空的列?在这个例子中,我需要上面的表格,但没有空列title

由于这些数据是动态的,有时可能会有另一列或多列为空,而我事先无法知道哪一列会这样。

【问题讨论】:

  • 不可能使列动态化,只能动态化行。
  • 除非您在存储过程中编写动态 SQL。
  • 考虑在应用程序代码中处理数据显示问题(如果是这样的话)
  • 一般事后在代码中处理,或者你可以用结果创建一个临时表并在临时表上删除列,然后从临时表中选择 *。

标签: mysql sql select dynamic-sql sql-null


【解决方案1】:

您可以通过以下方式识别“空”列:

select 
    count(title), 
    count(description),
    count(language),
    count(url),
    count(cagegory)
from imported_data

返回计数为 0 的列仅包含 null 值。然后,您可以根据需要删除相关列。

我不会得到 NULL 值,因为所有列都是 VARCHAR。

字符串列可能肯定包含null 值。如果你真的是指空字符串,而不是null,那么使用nullif()

select 
    count(nullif(title, '')), 
    count(nullif(description, '')),
    count(nullif(language, '')),
    count(nullif(url, '')),
    count(nullif(category, ''))
from imported_data

如果你想要完全动态的东西,那么考虑构建使用准备好的语句:

set @sql = null;

select concat_ws(', ',
    case when count(nullif(title, ''))       > 0 then 'title'       end,
    case when count(nullif(description, '')) > 0 then 'description' end,
    case when count(nullif(language, ''))    > 0 then 'language'    end,
    case when count(nullif(url, ''))         > 0 then 'url'         end,
    case when count(nullif(category, ''))    > 0 then 'category'    end
) into @sql
from imported_data;

set @sql = concat('select ', @sql, ' from imported_data');  
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;

【讨论】:

  • 如果SELECT 为空,如何将其排除在结果之外?
  • 您的第二个查询是计算空值,而不是非空值。所以当列只包含空值时它不会返回0,它将包含总行数。
  • @Barmar:对于只有空字符串(或 nulls)的列,第二个查询确实返回 0。至于解决问题本身,请参阅我的更新,它提供了基于动态 SQL 的解决方案。
  • 你准备好的陈述肯定是要走的路。我也在尝试类似的东西。您现在的解决方案的唯一问题是保留完整的空行(不存在空列)。还剩下什么来实现这一目标?谢谢!!
  • @GMB 我已经根据您的可能发布了一个答案。如果您认为有更好的方法,请编辑您的答案以考虑您的想法。再次感谢!!
【解决方案2】:

使用@GMB 答案作为基础,我在准备好的语句中添加了一种动态方法来检查 where 子句中是否有任何已验证字段为空,从而删除完整的空行,如下所示:

set @sql = null;

select concat_ws(', ',
    case when count(nullif(title, ''))       > 0 then 'title'       end,
    case when count(nullif(description, '')) > 0 then 'description' end,
    case when count(nullif(language, ''))    > 0 then 'language'    end,
    case when count(nullif(url, ''))         > 0 then 'url'         end,
    case when count(nullif(category, ''))    > 0 then 'category'    end
) into @sql
from imported_data;

set @sql = concat('select ', @sql, ' from imported_data where',
                 (
                    SELECT INSERT( GROUP_CONCAT('OR `', `COLUMN_NAME`, '`  != \'\' ' SEPARATOR ' '), 1, 3, '')
                    FROM `information_schema`.`COLUMNS`
                    WHERE `TABLE_SCHEMA` = 'mydb'
                        AND `TABLE_NAME` = 'imported_data'
                )
);  
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 2019-11-23
    相关资源
    最近更新 更多