Alle Spalten außer einer in MySQL auswählen?
Frage
Ich versuche, eine Select-Anweisung zu verwenden, um alle Spalten einer bestimmten MySQL-Tabelle bis auf eine abzurufen.Gibt es eine einfache Möglichkeit, dies zu tun?
BEARBEITEN:Diese Tabelle enthält 53 Spalten (NICHT MEIN DESIGN)
Lösung
Tatsächlich gibt es eine Möglichkeit, dafür benötigen Sie natürlich Berechtigungen ...
SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), '<columns_to_omit>,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table>' AND TABLE_SCHEMA = '<database>'), ' FROM <table>');
PREPARE stmt1 FROM @sql;
EXECUTE stmt1;
Ersetzen <table>, <database> and <columns_to_omit>
Andere Tipps
In MySQL-Definitionen (Handbuch) gibt es so etwas nicht.Aber wenn Sie eine wirklich große Anzahl von Spalten haben col1
, ..., col100
, Folgendes kann nützlich sein:
mysql> CREATE TEMPORARY TABLE temp_tb SELECT * FROM orig_tb;
mysql> ALTER TABLE temp_tb DROP col_x;
mysql> SELECT * FROM temp_tb;
Würde eine Ansicht in diesem Fall besser funktionieren?
CREATE VIEW vwTable
as
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Du kannst tun:
SELECT column1, column2, column4 FROM table WHERE whatever
ohne Spalte3 zu bekommen, obwohl Sie vielleicht nach einer allgemeineren Lösung gesucht haben?
Wenn Sie den Wert eines Feldes ausschließen möchten, z. B.Aus Sicherheitsgründen/sensiblen Informationen können Sie diese Spalte als Null abrufen.
z.B.
SELECT *, NULL AS salary FROM users
Soweit ich weiß, gibt es das nicht.Sie können so etwas tun:
SELECT col1, col2, col3, col4 FROM tbl
und wählen Sie manuell die gewünschten Spalten aus.Wenn Sie jedoch viele Spalten benötigen, möchten Sie möglicherweise Folgendes tun:
SELECT * FROM tbl
und ignoriere einfach, was du nicht willst.
In Ihrem speziellen Fall würde ich Folgendes vorschlagen:
SELECT * FROM tbl
es sei denn, Sie möchten nur ein paar Spalten.Wenn Sie nur vier Spalten möchten, dann:
SELECT col3, col6, col45, col 52 FROM tbl
wäre in Ordnung, aber wenn Sie 50 Spalten möchten, wäre jeder Code, der die Abfrage macht, (zu?) schwer lesbar.
Beim Ausprobieren der Lösungen von @Mahomedalid und @Junaid bin ich auf ein Problem gestoßen.Also habe ich darüber nachgedacht, es zu teilen.Wenn der Spaltenname wie beim Einchecken Leerzeichen oder Bindestriche enthält, schlägt die Abfrage fehl.Die einfache Problemumgehung besteht darin, Backticks um Spaltennamen herum zu verwenden.Die geänderte Abfrage ist unten
SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(CONCAT("`", COLUMN_NAME, "`")) FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;
Wenn die Spalte, die Sie nicht auswählen wollten, eine große Datenmenge enthielt und Sie sie aus Geschwindigkeitsgründen nicht einbeziehen wollten und Sie die anderen Spalten häufig auswählen, würde ich vorschlagen, dass Sie eine neue Tabelle erstellen mit dem einen Feld, das Sie normalerweise nicht mit einem Schlüssel zur Originaltabelle auswählen, und entfernen Sie das Feld aus der Originaltabelle.Verknüpfen Sie die Tabellen, wenn dieses zusätzliche Feld tatsächlich benötigt wird.
Du könntest benutzen BESCHREIBEN Sie my_table und verwenden Sie die Ergebnisse, um die SELECT-Anweisung dynamisch zu generieren.
Mein Hauptproblem sind die vielen Spalten, die ich beim Verknüpfen von Tabellen erhalte.Dies ist zwar nicht die Antwort auf Ihre Frage (wie man alle bis auf bestimmte Spalten auswählt). eins Tabelle), ich denke, es ist erwähnenswert, dass Sie angeben können table.
um alle Spalten aus einer bestimmten Tabelle abzurufen, anstatt sie nur anzugeben .
Hier ist ein Beispiel dafür, wie dies sehr nützlich sein könnte:
select users.*, phone.meta_value as phone, zipcode.meta_value as zipcode from users left join user_meta as phone on ( (users.user_id = phone.user_id) AND (phone.meta_key = 'phone') ) left join user_meta as zipcode on ( (users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode') )
Das Ergebnis sind alle Spalten aus der Benutzertabelle und zwei zusätzliche Spalten, die aus der Metatabelle verknüpft wurden.
Mir gefiel die Antwort von @Mahomedalid
außerdem wurde diese Tatsache im Kommentar von mitgeteilt @Bill Karwin
.Das mögliche Problem von @Jan Koritak
Es ist wahr, dass ich damit konfrontiert wurde, aber ich habe einen Trick dafür gefunden und möchte ihn hier allen mitteilen, die mit dem Problem konfrontiert sind.
Wir können die REPLACE-Funktion durch die Where-Klausel in der Unterabfrage der Prepared-Anweisung wie folgt ersetzen:
Unter Verwendung meines Tabellen- und Spaltennamens
SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;
Dadurch wird also nur das Feld ausgeschlossen id
aber nicht company_id
Ich hoffe, das hilft jedem, der nach einer Lösung sucht.
Grüße
Es empfiehlt sich, die Spalten anzugeben, die Sie abfragen, auch wenn Sie alle Spalten abfragen.
Daher würde ich vorschlagen, dass Sie den Namen jeder Spalte in der Anweisung angeben (mit Ausnahme der Spalte, die Sie nicht möchten).
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Mach einfach
SELECT * FROM table WHERE whatever
Fügen Sie dann die Spalte in Ihrer bevorzugten Programmiersprache ein:php
while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
unset($data["id"]);
foreach ($data as $k => $v) {
echo"$v,";
}
}
Ich bin mit der „einfachen“ Lösung einverstanden, alle Spalten aufzulisten, aber das kann mühsam sein und Tippfehler können viel Zeit verschwenden.Ich verwende eine Funktion „getTableColumns“, um die Namen meiner Spalten abzurufen, die zum Einfügen in eine Abfrage geeignet sind.Dann muss ich nur noch diejenigen löschen, die ich nicht möchte.
CREATE FUNCTION `getTableColumns`(tablename varchar(100))
RETURNS varchar(5000) CHARSET latin1
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE res VARCHAR(5000) DEFAULT "";
DECLARE col VARCHAR(200);
DECLARE cur1 CURSOR FOR
select COLUMN_NAME from information_schema.columns
where TABLE_NAME=@table AND TABLE_SCHEMA="yourdatabase" ORDER BY ORDINAL_POSITION;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO col;
IF NOT done THEN
set res = CONCAT(res,IF(LENGTH(res)>0,",",""),col);
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
RETURN res;
Ihr Ergebnis gibt beispielsweise eine durch Kommas getrennte Zeichenfolge zurück ...
Spalte1, Spalte2, Spalte3, Spalte4, ... Spalte53
Ich stimme zu, dass es nicht ausreicht Select *
, Wenn das, was Sie nicht benötigen, wie an anderer Stelle erwähnt, ein BLOB ist, möchten Sie nicht, dass sich dieser Overhead einschleicht.
Ich würde eine erstellen Sicht mit den erforderlichen Daten, dann können Sie Select *
bequem - sofern die Datenbanksoftware dies unterstützt.Andernfalls legen Sie die riesigen Datenmengen in einer anderen Tabelle ab.
Zuerst dachte ich, Sie könnten reguläre Ausdrücke verwenden, aber als ich das gelesen habe MYSQL-Dokumente es scheint, dass du das nicht kannst.Wenn ich Sie wäre, würde ich eine andere Sprache (z. B. PHP) verwenden, um eine Liste der Spalten zu generieren, die Sie abrufen möchten, sie als Zeichenfolge speichern und diese dann zum Generieren der SQL verwenden.
Ich wollte das auch, also habe ich stattdessen eine Funktion erstellt.
public function getColsExcept($table,$remove){
$res =mysql_query("SHOW COLUMNS FROM $table");
while($arr = mysql_fetch_assoc($res)){
$cols[] = $arr['Field'];
}
if(is_array($remove)){
$newCols = array_diff($cols,$remove);
return "`".implode("`,`",$newCols)."`";
}else{
$length = count($cols);
for($i=0;$i<$length;$i++){
if($cols[$i] == $remove)
unset($cols[$i]);
}
return "`".implode("`,`",$cols)."`";
}
}
So funktioniert es: Sie geben die Tabelle ein und dann eine Spalte, die Sie nicht möchten, oder wie in einem Array:array("id","name","whatevercolumn")
In select könnten Sie es also folgendermaßen verwenden:
mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");
oder
mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");
Stimmen Sie der Antwort von @Mahomedalid zu.Aber ich wollte nicht so etwas wie eine vorbereitete Anweisung machen und ich wollte nicht alle Felder ausfüllen.Was ich also hatte, war eine dumme Lösung.Gehen Sie zur Tabelle in phpmyadmin->sql->select, es wird die Abfrage kopiert, ersetzt und fertig!:) :)
Obwohl ich der Antwort von Thomas zustimme (+1 ;)), möchte ich den Vorbehalt hinzufügen, dass ich davon ausgehe, dass die Kolumne Sie ist nicht want enthält kaum Daten.Wenn es große Mengen an Text, XML oder binären Blobs enthält, nehmen Sie sich die Zeit, jede Spalte einzeln auszuwählen.Ihre Leistung wird sonst leiden.Prost!
Ja, obwohl es je nach Tabelle zu hohen I/O-Vorgängen kommen kann, habe ich hier eine Problemumgehung dafür gefunden.
Select *
into #temp
from table
alter table #temp drop column column_name
Select *
from #temp
Die von Mahomedalid gepostete Antwort hat ein kleines Problem:
Der Code der Ersetzungsfunktion ersetzte „<columns_to_delete>,
„durch „“ hat diese Ersetzung ein Problem, wenn das zu ersetzende Feld das letzte in der Concat-Zeichenfolge ist, da das letzte Feld nicht über das Zeichenkomma „“ verfügt und nicht aus der Zeichenfolge entfernt wird.
Mein Vorschlag:
SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME),
'<columns_to_delete>', '\'FIELD_REMOVED\'')
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '<table>'
AND TABLE_SCHEMA = '<database>'), ' FROM <table>');
Ersetzen <table>
, <database>
und `
Die entfernte Spalte wird durch die Zeichenfolge „FIELD_REMOVED“ ersetzt. In meinem Fall funktioniert dies, weil ich versucht habe, Speicherplatz zu sparen.(Das Feld, das ich entfernt habe, ist ein BLOB von etwa 1 MB)
Basierend auf der Antwort von @Mahomedalid habe ich einige Verbesserungen vorgenommen, um „Alle Spalten außer einigen in MySQL auswählen“ zu unterstützen.
SET @database = 'database_name';
SET @tablename = 'table_name';
SET @cols2delete = 'col1,col2,col3';
SET @sql = CONCAT(
'SELECT ',
(
SELECT GROUP_CONCAT( IF(FIND_IN_SET(COLUMN_NAME, @cols2delete), NULL, COLUMN_NAME ) )
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tablename AND TABLE_SCHEMA = @database
),
' FROM ',
@tablename);
SELECT @sql;
Wenn Sie viele Spalten haben, verwenden Sie diese SQL, um group_concat_max_len zu ändern
SET @@group_concat_max_len = 2048;
Vielleicht habe ich eine Lösung dafür Jan Koritaks auf Diskrepanz hingewiesen
SELECT CONCAT('SELECT ',
( SELECT GROUP_CONCAT(t.col)
FROM
(
SELECT CASE
WHEN COLUMN_NAME = 'eid' THEN NULL
ELSE COLUMN_NAME
END AS col
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
) t
WHERE t.col IS NOT NULL) ,
' FROM employee' );
Tisch :
SELECT table_name,column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
================================
table_name column_name
employee eid
employee name_eid
employee sal
================================
Abfrageergebnis:
'SELECT name_eid,sal FROM employee'
Wenn es sich immer um dieselbe Spalte handelt, können Sie eine Ansicht erstellen, in der sie nicht enthalten ist.
Ansonsten nein, das glaube ich nicht.
Wenn Sie möchten, können Sie SQL zum Generieren von SQL verwenden und das erzeugte SQL auswerten.Dies ist eine allgemeine Lösung, da sie die Spaltennamen aus dem Informationsschema extrahiert.Hier ist ein Beispiel aus der Unix-Befehlszeile.
Ersetzen
- MYSQL mit Ihrem MySQL-Befehl
- TABLE mit dem Tabellennamen
- EXCLUDEDFIELD mit ausgeschlossenem Feldnamen
echo $(echo 'select concat("select ", group_concat(column_name) , " from TABLE") from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1) | MYSQL
Sie müssen die Spaltennamen auf diese Weise tatsächlich nur einmal extrahieren, um die Spaltenliste mit Ausnahme dieser Spalte zu erstellen, und dann einfach die von Ihnen erstellte Abfrage verwenden.
Also so etwas wie:
column_list=$(echo 'select group_concat(column_name) from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1)
Jetzt können Sie es wiederverwenden $column_list
Zeichenfolge in Abfragen, die Sie erstellen.
Ich möchte einen weiteren Gesichtspunkt hinzufügen, um dieses Problem zu lösen, insbesondere wenn Sie eine kleine Anzahl von Spalten entfernen müssen.
Sie könnten ein DB-Tool wie verwenden MySQL-Workbench Um die Select-Anweisung für Sie zu generieren, müssen Sie lediglich diese Spalten für die generierte Anweisung manuell entfernen und sie in Ihr SQL-Skript kopieren.
In MySQL Workbench wird es wie folgt generiert:
Klicken Sie mit der rechten Maustaste auf die Tabelle -> An SQL-Editor senden -> Alle Anweisungen auswählen.
Die akzeptierte Antwort weist mehrere Mängel auf.
- Es schlägt fehl, wenn die Tabellen- oder Spaltennamen Backticks erfordern
- Es schlägt fehl, wenn die Spalte, die Sie auslassen möchten, die letzte in der Liste ist
- Der Tabellenname muss zweimal aufgeführt werden (einmal für die Auswahl und einmal für den Abfragetext), was überflüssig und unnötig ist
- Es kann möglicherweise Spaltennamen im zurückgeben Falsche Bestellung
Alle diese Probleme können durch einfaches Einbeziehen von Backticks in das gelöst werden SEPARATOR
für dein GROUP_CONCAT
und mit a WHERE
Zustand statt REPLACE()
.Für meine Zwecke (und ich stelle mir viele andere vor) wollte ich, dass die Spaltennamen in derselben Reihenfolge zurückgegeben werden, in der sie in der Tabelle selbst erscheinen.Um dies zu erreichen, verwenden wir hier eine explizite ORDER BY
Klausel innerhalb der GROUP_CONCAT()
Funktion:
SELECT CONCAT(
'SELECT `',
GROUP_CONCAT(COLUMN_NAME ORDER BY `ORDINAL_POSITION` SEPARATOR '`,`'),
'` FROM `',
`TABLE_SCHEMA`,
'`.`',
TABLE_NAME,
'`;'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE `TABLE_SCHEMA` = 'my_database'
AND `TABLE_NAME` = 'my_table'
AND `COLUMN_NAME` != 'column_to_omit';
Ich bin ziemlich spät dran, eine Antwort darauf zu finden. Ich habe es immer so gemacht, und ehrlich gesagt ist es 100-mal besser und übersichtlicher als die beste Antwort. Ich hoffe nur, dass es jemand sieht.Und finde es nützlich
//create an array, we will call it here.
$here = array();
//create an SQL query in order to get all of the column names
$SQL = "SHOW COLUMNS FROM Table";
//put all of the column names in the array
foreach($conn->query($SQL) as $row) {
$here[] = $row[0];
}
//now search through the array containing the column names for the name of the column, in this case i used the common ID field as an example
$key = array_search('ID', $here);
//now delete the entry
unset($here[$key]);
Select * ist ein SQL-Antimuster.Es sollte aus folgenden Gründen nicht im Produktionscode verwendet werden:
Die Bearbeitung dauert etwas länger.Wenn Dinge millionenfach ausgeführt werden, können diese winzigen Teile von Bedeutung sein.Eine langsame Datenbank, bei der die Langsamkeit durch diese Art von schlampiger Codierung verursacht wird, ist am schwierigsten für die Leistungsoptimierung.
Dies bedeutet, dass Sie wahrscheinlich mehr Daten senden, als Sie benötigen, was zu Server- und Netzwerkengpässen führt.Wenn Sie über einen Inner Join verfügen, liegt die Wahrscheinlichkeit, dass Sie mehr Daten senden, als Sie benötigen, bei 100 %.
Dies verursacht Wartungsprobleme, insbesondere wenn Sie neue Spalten hinzugefügt haben, die nicht überall angezeigt werden sollen.Wenn Sie außerdem eine neue Spalte haben, müssen Sie möglicherweise etwas an der Schnittstelle vornehmen, um zu bestimmen, was mit dieser Spalte geschehen soll.
Es kann Ansichten beschädigen (ich weiß, dass dies auf SQL-Server zutrifft, es kann jedoch auf MySQL zutreffen oder auch nicht).
Wenn jemand dumm genug ist, die Tabellen mit den Spalten in einer anderen Reihenfolge neu zu erstellen (was Sie nicht tun sollten, aber es kommt ständig vor), können alle Arten von Code kaputt gehen.Insbesondere Code für eine Einfügung, bei der Sie beispielsweise plötzlich die Stadt in das Feld „Adresse_3“ einfügen, da die Datenbank ohne Angabe nur in der Reihenfolge der Spalten vorgehen kann.Das ist schon schlimm genug, wenn sich die Datentypen ändern, aber noch schlimmer, wenn die ausgetauschten Spalten denselben Datentyp haben, weil es passieren kann, dass man irgendwann fehlerhafte Daten einfügt, deren Bereinigung ein Durcheinander ist.Sie müssen sich um die Datenintegrität kümmern.
Wenn es in einer Einfügung verwendet wird, wird die Einfügung unterbrochen, wenn in einer Tabelle eine neue Spalte hinzugefügt wird, in der anderen jedoch nicht.
Es könnte Auslöser beschädigen.Triggerprobleme können schwierig zu diagnostizieren sein.
Addieren Sie das alles mit der Zeit, die zum Hinzufügen der Spaltennamen benötigt wird (vielleicht verfügen Sie sogar über eine Schnittstelle, die es Ihnen ermöglicht, die Spaltennamen per Drag-and-Drop zu verschieben (ich weiß, dass ich das in SQL Server mache, ich wette, es gibt eine Möglichkeit, dies zu tun). Dies ist ein Tool, das Sie zum Schreiben von MySQL-Abfragen verwenden.) Mal sehen: „Ich kann Wartungsprobleme verursachen, ich kann Leistungsprobleme verursachen und ich kann Probleme mit der Datenintegrität verursachen, aber hey, ich habe fünf Minuten Entwicklungszeit gespart.“ Wirklich einfach ausgedrückt in den spezifischen Spalten, die Sie möchten.
Ich empfehle Ihnen außerdem, dieses Buch zu lesen:http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers-ebook/dp/B00A376BB2/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1389896688&sr=1-1&keywords=sql+antipatterns