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)

War es hilfreich?

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top