Lassen Sie uns eine Beispieltabelle auf meinem Computer auswählen:
mysql> show create table weisci_jaws_staging2.users\G
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL DEFAULT '',
`passwd` varchar(32) NOT NULL DEFAULT '',
`user_type` tinyint(4) DEFAULT '2',
`recovery_key` varchar(48) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
`timezone` varchar(5) DEFAULT NULL,
`language` varchar(5) DEFAULT NULL,
`theme` varchar(24) DEFAULT NULL,
`editor` varchar(24) DEFAULT NULL,
`last_login` datetime DEFAULT NULL,
`createtime` datetime DEFAULT NULL,
`updatetime` datetime DEFAULT NULL,
`change_passwd` tinyint(1) NOT NULL DEFAULT '1',
`never_expire` tinyint(1) NOT NULL DEFAULT '1',
`bad_passwd_count` smallint(6) DEFAULT '0',
`last_access` bigint(20) DEFAULT '0',
`enabled` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `users_username_idx` (`username`)
) ENGINE=MyISAM AUTO_INCREMENT=160 DEFAULT CHARSET=utf8
1 row in set (0.02 sec)
mysql> select count(1) from weisci_jaws_staging2.users;
+----------+
| count(1) |
+----------+
| 117 |
+----------+
1 row in set (0.00 sec)
mysql>
Bei dieser Tabelle gibt es zwei Fragen:
- Welche Spalten sind nullwertfähig?
- Welche Spalten sind nicht nullwertfähig?
Diese Abfrage wird für Sie herausfinden:
select is_nullable,GROUP_CONCAT(column_name) column_list
from information_schema.columns
where table_schema = 'weisci_jaws_staging2'
and table_name = 'users'
group by is_nullable;
Überprüfen Sie das Ergebnis dieser Abfrage für die Tabelle:
mysql> select is_nullable,GROUP_CONCAT(column_name) column_list
-> from information_schema.columns
-> where table_schema = 'weisci_jaws_staging2'
-> and table_name = 'users'
-> group by is_nullable;
+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| is_nullable | column_list |
+-------------+------------------------------------------------------------------------------------------------------------------------------------+
| NO | id,never_expire,change_passwd,enabled,username,passwd |
| YES | recovery_key,last_access,bad_passwd_count,updatetime,createtime,last_login,editor,user_type,language,timezone,url,email,name,theme |
+-------------+------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.01 sec)
mysql>
OK, wir haben zwei Listen. Was lernen wir daraus?
- Wenn Sie zwei Listen erhalten, müssen Sie die tatsächliche Tabelle nicht überprüfen, da die Tabelle per Definition Nicht-NULL-Spalten enthält.
- Wenn Sie eine Liste erhalten, dann
- Wenn Sie nur is_nullable = 'NO' erhalten, müssen Sie die tatsächliche Tabelle nicht überprüfen, da die Tabelle per Definition Nicht-NULL-Spalten enthält.
- Wenn Sie nur is_nullable = 'YES' erhalten, wäre die tatsächliche Tabelle etwas spröde. Es würde keinen PRIMÄREN SCHLÜSSEL geben, du arme, gequälte Seele !!! JETZT müssen Sie jede Zeile aus der tatsächlichen Tabelle lesen.
Wenn Sie nur nach Nicht-Null-Spalten suchen, ist dies Ihre gewünschte Abfrage:
select GROUP_CONCAT(column_name) nonnull_columns
from information_schema.columns
where table_schema = 'weisci_jaws_staging2'
and table_name = 'users'
and is_nullable = 'NO';
Hier ist die Ausgabe dieser Abfrage:
mysql> select GROUP_CONCAT(column_name) nonnull_columns
-> from information_schema.columns
-> where table_schema = 'weisci_jaws_staging2'
-> and table_name = 'users'
-> and is_nullable = 'NO';
+-------------------------------------------------------+
| nonnull_columns |
+-------------------------------------------------------+
| id,username,passwd,change_passwd,never_expire,enabled |
+-------------------------------------------------------+
1 row in set (0.01 sec)
mysql>
Wenn Sie GROUP_CONCAT entfernen, erhalten Sie Folgendes:
mysql> select column_name nonnull_column
-> from information_schema.columns
-> where table_schema = 'weisci_jaws_staging2'
-> and table_name = 'users'
-> and is_nullable = 'NO';
+----------------+
| nonnull_column |
+----------------+
| id |
| username |
| passwd |
| change_passwd |
| never_expire |
| enabled |
+----------------+
6 rows in set (0.01 sec)
mysql>
Versuche es !!!
HINWEIS : Bitte beachten Sie, dass ich den Dateninhalt der tatsächlichen Tabelle nicht lesen muss. Das ist weitaus effizienter als das Lesen der gesamten Tabelle.
UPDATE 15.11.2012 13:40 EDT
Der Code aus der Antwort von @ sensware enthält NULL
Spalten. Die ursprüngliche Frage wurde nach non-NULL
Spalten gestellt. Ich habe den Code erweitert, um nur meine Tabelle zu testen:
SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation
SELECT CONCAT(
'SELECT * FROM ('
, GROUP_CONCAT(
CONCAT(
'SELECT ', QUOTE(TABLE_NAME), ' AS `table`,'
, 'IF('
, 'COUNT(`', REPLACE(COLUMN_NAME, '`', '``'), '`),'
, 'NULL,'
, QUOTE(COLUMN_NAME)
, ') AS `column` '
, 'FROM `',
REPLACE(TABLE_SCHEMA, '`', '``'), '`.`',
REPLACE(TABLE_NAME, '`', '``'), '`'
)
SEPARATOR ' UNION ALL '
)
, ') t WHERE `column` IS NOT NULL'
)
INTO @sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'weisci_jaws_staging2'
AND TABLE_NAME = 'users';
SELECT @sql\G
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Hier ist die Ausgabe:
mysql> SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CONCAT(
-> 'SELECT * FROM ('
-> , GROUP_CONCAT(
-> CONCAT(
-> 'SELECT ', QUOTE(TABLE_NAME), ' AS `table`,'
-> , 'IF('
-> , 'COUNT(`', REPLACE(COLUMN_NAME, '`', '``'), '`),'
-> , 'NULL,'
-> , QUOTE(COLUMN_NAME)
-> , ') AS `column` '
-> , 'FROM `',
-> REPLACE(TABLE_SCHEMA, '`', '``'), '`.`',
-> REPLACE(TABLE_NAME, '`', '``'), '`'
-> )
-> SEPARATOR ' UNION ALL '
-> )
-> , ') t WHERE `column` IS NOT NULL'
-> )
-> INTO @sql
-> FROM INFORMATION_SCHEMA.COLUMNS
-> WHERE TABLE_SCHEMA = 'weisci_jaws_staging2'
-> AND TABLE_NAME = 'users';
Query OK, 1 row affected (0.02 sec)
mysql> SELECT @sql\G
*************************** 1. row ***************************
@sql: SELECT * FROM (SELECT 'users' AS `table`,IF(COUNT(`id`),NULL,'id') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`username`),NULL,'username') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`passwd`),NULL,'passwd') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`user_type`),NULL,'user_type') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`recovery_key`),NULL,'recovery_key') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`name`),NULL,'name') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`email`),NULL,'email') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`url`),NULL,'url') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`timezone`),NULL,'timezone') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`language`),NULL,'language') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`theme`),NULL,'theme') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`editor`),NULL,'editor') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`last_login`),NULL,'last_login') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`createtime`),NULL,'createtime') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`updatetime`),NULL,'updatetime') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`change_passwd`),NULL,'change_passwd') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`never_expire`),NULL,'never_expire') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`bad_passwd_count`),NULL,'bad_passwd_count') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`last_access`),NULL,'last_access') AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`enabled`),NULL,'enabled') AS `column` FROM `weisci_jaws_staging2`.`users`) t WHERE `column` IS NOT NULL
1 row in set (0.00 sec)
mysql> PREPARE stmt FROM @sql;
Query OK, 0 rows affected (0.01 sec)
Statement prepared
mysql> EXECUTE stmt;
+-------+--------+
| table | column |
+-------+--------+
| users | theme |
+-------+--------+
1 row in set (0.00 sec)
mysql> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
mysql>
Dies ergibt NULL-Spalten. Die ursprüngliche Frage bezog sich auf Nicht-NULL-Spalten. Ich werde den Code in "Nicht-NULL" ändern. Ich mache das, indem ich die Reihenfolge der IF..COUNT
:
SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation
SELECT CONCAT(
'SELECT * FROM ('
, GROUP_CONCAT(
CONCAT(
'SELECT ', QUOTE(TABLE_NAME), ' AS `table`,'
, 'IF('
, 'COUNT(`', REPLACE(COLUMN_NAME, '`', '``'), '`),'
, QUOTE(COLUMN_NAME)
, ',NULL'
, ') AS `column` '
, 'FROM `',
REPLACE(TABLE_SCHEMA, '`', '``'), '`.`',
REPLACE(TABLE_NAME, '`', '``'), '`'
)
SEPARATOR ' UNION ALL '
)
, ') t WHERE `column` IS NOT NULL'
)
INTO @sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'weisci_jaws_staging2'
AND TABLE_NAME = 'users';
SELECT @sql\G
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Lass es uns jetzt laufen lassen ...
mysql> SET group_concat_max_len = 4294967295; -- to overcome default 1KB limitation
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT CONCAT(
-> 'SELECT * FROM ('
-> , GROUP_CONCAT(
-> CONCAT(
-> 'SELECT ', QUOTE(TABLE_NAME), ' AS `table`,'
-> , 'IF('
-> , 'COUNT(`', REPLACE(COLUMN_NAME, '`', '``'), '`),'
-> , QUOTE(COLUMN_NAME)
-> , ',NULL'
-> , ') AS `column` '
-> , 'FROM `',
-> REPLACE(TABLE_SCHEMA, '`', '``'), '`.`',
-> REPLACE(TABLE_NAME, '`', '``'), '`'
-> )
-> SEPARATOR ' UNION ALL '
-> )
-> , ') t WHERE `column` IS NOT NULL'
-> )
-> INTO @sql
-> FROM INFORMATION_SCHEMA.COLUMNS
-> WHERE TABLE_SCHEMA = 'weisci_jaws_staging2'
-> AND TABLE_NAME = 'users';
Query OK, 1 row affected (0.01 sec)
mysql> SELECT @sql\G
*************************** 1. row ***************************
@sql: SELECT * FROM (SELECT 'users' AS `table`,IF(COUNT(`id`),'id',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`username`),'username',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`passwd`),'passwd',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`user_type`),'user_type',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`recovery_key`),'recovery_key',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`name`),'name',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`email`),'email',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`url`),'url',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`timezone`),'timezone',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`language`),'language',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`theme`),'theme',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`editor`),'editor',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`last_login`),'last_login',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`createtime`),'createtime',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`updatetime`),'updatetime',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`change_passwd`),'change_passwd',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`never_expire`),'never_expire',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`bad_passwd_count`),'bad_passwd_count',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`last_access`),'last_access',NULL) AS `column` FROM `weisci_jaws_staging2`.`users` UNION ALL SELECT 'users' AS `table`,IF(COUNT(`enabled`),'enabled',NULL) AS `column` FROM `weisci_jaws_staging2`.`users`) t WHERE `column` IS NOT NULL
1 row in set (0.00 sec)
mysql> PREPARE stmt FROM @sql;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE stmt;
+-------+------------------+
| table | column |
+-------+------------------+
| users | id |
| users | username |
| users | passwd |
| users | user_type |
| users | recovery_key |
| users | name |
| users | email |
| users | url |
| users | timezone |
| users | language |
| users | editor |
| users | last_login |
| users | createtime |
| users | updatetime |
| users | change_passwd |
| users | never_expire |
| users | bad_passwd_count |
| users | last_access |
| users | enabled |
+-------+------------------+
19 rows in set (0.01 sec)
mysql> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)
mysql>
OK, es funktioniert jetzt. Es liegt noch ein Problem vor. Die Abfrage erfordert das Lesen der gesamten Tabelle. Meine Testtabelle hat nur 117 Zeilen und 20 Spalten. Was ist mit größeren Tabellen mit Millionen von Zeilen oder Dutzenden von Spalten ? Ich werde nicht spekulieren, weil ich weiß, dass der Code um Größenordnungen schlechter wäre.
Deshalb empfehle ich meine Antwort
select GROUP_CONCAT(column_name) nonnull_columns
from information_schema.columns
where table_schema = 'weisci_jaws_staging2'
and table_name = 'users'
and is_nullable = 'NO';
oder
select column_name nonnull_column
from information_schema.columns
where table_schema = 'weisci_jaws_staging2'
and table_name = 'users'
and is_nullable = 'NO';
weil der tatsächliche Dateninhalt nicht überprüft werden muss.
Der erweiterte Code, den ich erstellt habe, sollte nur für eine Tabelle verwendet werden, in der alle Spalten NULL
Werte zulassen , was äußerst selten ist.