Подтвердить что ты не робот

Найти все те столбцы, которые имеют только нулевые значения, в таблице MySQL

Ситуация такова:

У меня есть значительное количество таблиц, каждое из которых содержит значительное количество столбцов. Мне нужно иметь дело с этой старой и устаревшей базой данных для новой системы, и я ищу способ устранить все столбцы, которые, по-видимому, никогда не использовались.

Я хочу сделать это, отфильтровывая все столбцы, которые имеют значение в любой заданной строке, оставляя мне набор столбцов, где значение равно NULL во всех строках. Конечно, я мог бы вручную отсортировать каждый столбец по убыванию, но это займет слишком много времени, поскольку я имею дело с множеством таблиц и столбцов. Я оцениваю его как 400 таблиц с до 50 (!) Столбцов на таблицу.

Есть ли способ получить эту информацию из information_schema?

EDIT:

Вот пример:

column_a    column_b    column_c    column_d
NULL        NULL        NULL        1
NULL        1           NULL        1
NULL        1           NULL        NULL
NULL        NULL        NULL        NULL

Вывод должен быть "column_a" и "column_c", поскольку они являются единственными столбцами без каких-либо значений.

4b9b3361

Ответ 1

Вы можете избежать использования процедуры путем динамического создания (из таблицы INFORMATION_SCHEMA.COLUMNS) строки, содержащей SQL, которую вы хотите выполнить, а затем подготовка инструкции из этой строки и ее выполнение.

SQL, который мы хотим построить, будет выглядеть так:

SELECT * FROM (
  SELECT 'tableA' AS `table`,
         IF(COUNT(`column_a`), NULL, 'column_a') AS `column`
  FROM   tableA
UNION ALL
  SELECT 'tableB' AS `table`,
         IF(COUNT(`column_b`), NULL, 'column_b') AS `column`
  FROM   tableB
UNION ALL
  -- etc.
) t WHERE `column` IS NOT NULL

Это можно сделать, используя следующее:

SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation

SELECT CONCAT(
         'SELECT * FROM ('
       ,  GROUP_CONCAT(
            'SELECT ', QUOTE(TABLE_NAME), ' AS `table`,'
          , 'IF('
          ,   'COUNT(`', REPLACE(COLUMN_NAME, '`', '``'), '`),'
          ,   'NULL,'
          ,    QUOTE(COLUMN_NAME)
          , ') AS `column` '
          , 'FROM `', REPLACE(TABLE_NAME, '`', '``'), '`'
          SEPARATOR ' UNION ALL '
         )
       , ') t WHERE `column` IS NOT NULL'
       )
INTO   @sql
FROM   INFORMATION_SCHEMA.COLUMNS
WHERE  TABLE_SCHEMA = DATABASE();

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Посмотрите на sqlfiddle.

Ответ 2

Я не являюсь экспертом в процедурах SQL, поэтому даю общую идею, используя SQL-запросы и PHP/python script.

  • используйте SHOW TABLES или какой-либо другой запрос в базе данных INFORMATION_SCHEMA, чтобы получить все таблицы в вашей базе данных MY_DATABASE

  • выполнить запрос для создания оператора для получения всех имен столбцов в определенной таблице, это будет использоваться в следующем запросе.

 SELECT Group_concat(Concat( "MAX(", column_name, ")" ))
         FROM   information_schema.columns
         WHERE  table_schema = 'MY_DATABSE'
                AND table_name = 'MY_TABLE'
         ORDER  BY table_name,ordinal_position
  • Вы получите результат, например MAX(column_a),MAX(column_b),MAX(column_c),MAX(column_d)

  • Используйте этот вывод для генерации окончательного запроса:

SELECT Max (column_a), Макс (столбец_b), Макс (столбец_c), Макс (столбец_d) FROM MY_DATABASE.MY_TABLE

Вывод будет:

   MAX(column_a)    MAX(column_b)   MAX(column_c)   MAX(column_d)
     NULL            1           NULL                1
  • Все столбцы с максимальным значением NULL - это те, которые имеют все значения NULL

Ответ 3

Демо-ссылка SQL Fiddle

Я создал 4 таблицы. Три для демонстрации и одна nullcolumns являются обязательной частью решения. Среди трех таблиц только salary и dept имеют столбцы со всеми значениями null (вы можете посмотреть их script).

Обязательная таблица и процедура даны в конце

Вы можете скопировать вставку и запустить (обязательную часть или все) как sql (просто вам нужно изменить разделитель на // ) в вашей нужной базе данных на вашем локальном хосте, а затем --- call get(); и посмотреть результаты

CREATE TABLE IF NOT EXISTS `dept` (
  `did` int(11) NOT NULL,
  `dname` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`did`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


INSERT INTO `dept` (`did`, `dname`) VALUES
(1, NULL),
(2, NULL),
(3, NULL),
(4, NULL),
(5, NULL);

CREATE TABLE IF NOT EXISTS `emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ename` varchar(50) NOT NULL,
  `did` int(11) NOT NULL,
  PRIMARY KEY (`ename`),
  KEY `deptid` (`did`),
  KEY `id` (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;


INSERT INTO `emp` (`id`, `ename`, `did`) VALUES
(1, 'e1', 4),
(2, 'e2', 4),
(3, 'e3', 2),
(4, 'e4', 4),
(5, 'e5', 3);


CREATE TABLE IF NOT EXISTS `salary` (
  `EmpCode` varchar(50) NOT NULL,
  `Amount` int(11) DEFAULT NULL,
  `Date` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `salary` (`EmpCode`, `Amount`, `Date`) VALUES
('1', 344, NULL),
('2', NULL, NULL);

------------------------------------------------------------------------
------------------------------------------------------------------------

CREATE TABLE IF NOT EXISTS `nullcolumns` (
  `Table_Name` varchar(100) NOT NULL,
  `Column_Name` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--Only one procedure Now
CREATE PROCEDURE get(dn varchar(100))
BEGIN
declare c1 int; declare b1 int default 0; declare tn varchar(30);
declare c2 int; declare b2 int; declare cn varchar(30);

select count(*) into c1 from information_schema.tables where table_schema=dn;
delete from nullcolumns;
while b1<c1 do
select table_name into tn from information_schema.tables where
table_schema=dn limit b1,1;        

select count(*) into c2 from information_schema.columns where
table_schema=dn and table_name=tn;
set b2=0;
while b2<c2 do
select column_name into cn from information_schema.columns where
table_schema=dn and table_name=tn limit b2,1;

set @nor := 0;
set @query := concat("select count(*) into @nor from ", dn,".",tn);
prepare s1 from @query;
execute s1;deallocate prepare s1;

if @nor>0 then set @res := 0;
set @query := concat("select ((select max(",cn,") from ", dn,".",tn,")
is NULL) into @res");
prepare s1 from @query;
execute s1;deallocate prepare s1;

if @res=1 then
insert into nullcolumns values(tn,cn);
end if; end if;

set b2=b2+1;
end while;

set b1=b1+1;
end while;
select * from nullcolumns;
END;

Вы легко можете легко выполнить хранимую процедуру как sql в своем phpmyadin ', так как это просто измените разделители (внизу блока SQL quesry) на //Then

call get();

И Наслаждайтесь:)

Теперь вы можете увидеть таблицу nullcolumns, отображающую все столбцы со 100/100 нулевыми значениями вместе с таблицей Имена

В коде процедуры if @nor>0 ограничивается, что пустая таблица не должна включаться в результаты, вы можете удалить это ограничение.

Ответ 4

Вы можете использовать поведение функции агрегации COUNT в отношении NULL. Передавая поле в качестве аргумента, функция COUNT возвращает количество значений, отличных от NULL, в то время как COUNT (*) возвращает общее количество строк. Таким образом, вы можете рассчитать отношение NULL к "приемлемым" значениям.

Я приведу пример со следующей структурой таблицы:

CREATE TABLE `t1` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `col_1` int(10) unsigned DEFAULT NULL,
   `col_2` int(10) unsigned DEFAULT NULL,
   PRIMARY KEY (`id`)
) ;

-- let fill the table with random values
INSERT INTO t1(col_1,col_2) VALUES(1,2);
INSERT INTO t1(col_1,col_2) 
SELECT 
IF(RAND() > 0.5, NULL ,FLOOR(RAND()*1000), 
IF(RAND() > 0.5, NULL ,FLOOR(RAND()*1000) FROM t1;

-- run the last INSERT-SELECT statement a few times
SELECT COUNT(col_1)/COUNT(*) AS col_1_ratio, 
COUNT(col_2)/COUNT(*) AS col_2_ratio FROM t1;

Вы можете написать функцию, которая автоматически создает запрос из INFORMATION_SCHEMA, передав имя таблицы в качестве входной переменной. Здесь, как получить данные структуры непосредственно из таблиц INFORMATION_SCHEMA:

SET @query:=CONCAT("SELECT @column_list:=GROUP_CONCAT(col) FROM (
SELECT CONCAT('COUNT(',c.COLUMN_NAME,')/COUNT(*)') AS col
FROM INFORMATION_SCHEMA.COLUMNS c 
WHERE NOT COLUMN_KEY IN('PRI') AND TABLE_SCHEMA=DATABASE() 
AND TABLE_NAME='t1' ORDER BY ORDINAL_POSITION ) q");
PREPARE COLUMN_SELECT FROM @query;
EXECUTE COLUMN_SELECT;
SET @null_counters_sql := CONCAT('SELECT ',@column_list, ' FROM t1');
PREPARE NULL_COUNTERS FROM @null_counters_sql;
EXECUTE NULL_COUNTERS;

Ответ 5

Я думаю, вы можете сделать это с помощью GROUP_CONCAT и GROUP BY:

select length(replace(GROUP_CONCAT(my_col), ',', ''))
from my_table
group by my_col

(непроверенные)

EDIT: документы, похоже, не указывают, что GROUP_CONCAT нуждается в соответствующей GROUP BY, поэтому попробуйте следующее:

select 
    length(replace(GROUP_CONCAT(col_a), ',', '')) as len_a
    , length(replace(GROUP_CONCAT(col_b), ',', '')) as len_b
    , length(replace(GROUP_CONCAT(col_c), ',', '')) as Len_c
from my_table

Ответ 6

select column_name
from user_tab_columns
where table_name='Table_name' and num_nulls>=1;

Просто с помощью простого запроса вы получите эти два столбца.