MySQL, Überprüfen Sie, ob eine Spalte in einer Tabelle mit SQL vorhanden ist

130

Ich versuche, eine Abfrage zu schreiben, die überprüft, ob eine bestimmte Tabelle in MySQL eine bestimmte Spalte enthält, und wenn nicht, erstellen Sie sie. Sonst nichts tun. Dies ist wirklich eine einfache Prozedur in jeder Datenbank der Enterprise-Klasse, aber MySQL scheint eine Ausnahme zu sein.

Ich dachte so etwas

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.COLUMNS 
           WHERE TABLE_NAME='prefix_topic' AND column_name='topic_last_update') 
BEGIN 
ALTER TABLE `prefix_topic` ADD `topic_last_update` DATETIME NOT NULL;
UPDATE `prefix_topic` SET `topic_last_update` = `topic_date_add`;
END;

würde funktionieren, aber es scheitert schlecht. Gibt es einen Weg?

Clops
quelle
Warum nicht einfach erstellen? Wenn es existiert, schlägt die Erstellung fehl, aber es ist Ihnen egal.
Brian Hooper
Die Erstellung findet innerhalb einer Transaktion statt und der Fehler beendet die gesamte Transaktion, traurig, aber wahr
Clops
@haim - als für die Headups, aber die in Ihrem Link vorgeschlagene Abfrage funktioniert nur innerhalb einer Prozedur :(
Clops
2
DDL-Anweisungen verursachen ein implizites Festschreiben in der aktuellen Transaktion. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

Antworten:

259

Das funktioniert gut für mich.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Mit PHP wäre es so etwas wie ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Mfoo
quelle
8
Die Frage ist nicht, wie man das mit PHP + SQL oder Java + SQL macht, sondern wie man das mit reinem SQL / MySQL macht, daher die Abwertung
Yuriy Nakonechnyy
61
Sie beantworten die Frage + einige Informationen, die mir und wahrscheinlich anderen geholfen haben, +1
Francisco Presencia
@Mfoo Danke Mfoo, du hast meinen Tag gerettet! Funktioniert wie Charme. Eine der besten Lösungen neben der Erstellung von Prozeduren für diese Aufgabe.
Webblover
8
Yura: Die reine SQL / MySQL-Antwort ist der erste Teil, in dem er sagt, dass "SHOW COLUMNS FROM table LIKE 'fieldname'" verwendet wird. Sie können den PHP-Code ignorieren. Dies ist nur ein Beispiel für eine Möglichkeit, das Ergebnis abzurufen und zu interpretieren, wenn Sie zufällig PHP verwenden.
Orrd
1
@codenamezero Ich gehe davon aus, dass Sie sich auf die Verwendung von MSSQL beziehen. Diese Frage betraf MySQL. beziehen sich auf diesen Beitrag für MSSQL
Mfoo
158

@ Julio

Vielen Dank für das SQL-Beispiel. Ich habe die Abfrage ausprobiert und denke, dass eine kleine Änderung erforderlich ist, damit sie ordnungsgemäß funktioniert.

SELECT * 
FROM information_schema.COLUMNS 
WHERE 
    TABLE_SCHEMA = 'db_name' 
AND TABLE_NAME = 'table_name' 
AND COLUMN_NAME = 'column_name'

Das hat bei mir funktioniert.

Vielen Dank!

Iain
quelle
Aus meiner begrenzten Forschung geht hervor, dass nicht alle Hosting-Umgebungen über eine information_schema-Datenbank verfügen. Alle von mir verwendeten cpanel-Umgebungen haben es. Diese bereitgestellte Lösung hängt von der vorhandenen Datenbank ab.
cardi777
2
Diese Antwort ist besser als die Verwendung von "SHOW COLUMNS", da im Gegensatz zu MySQL-spezifischen SHOW COLUMNS die ANSI-Standardmethode zum Abrufen von Tabelleninformationen verwendet wird. Diese Lösung funktioniert also mit anderen Datenbanken. Die Verwendung von "information_schema" klingt seltsam und Sie würden denken, es wäre nicht die Standard-SQL-Methode, dies zu tun, aber es ist so.
Orrd
5
Beachten Sie, dass Sie mit dieser Antwort nur Informationen über die Existenz der Spalte erhalten. Wenn Sie einige DDL-Anweisungen bedingt ausführen möchten, müssen Sie das Ganze in eine Prozedur einschließen , die Anweisungen wie IFusw. zulässt. Ein Beispiel für das Umschließen einer Prozedur finden Sie unter stackoverflow.com/questions/7384711/… der Test für die Spalte und die bedingte DML-Anweisung.
Christopher Schultz
@Iain: stackoverflow.com/questions/32962149/… Ich habe Ihre Antwort weitergeleitet
Amar Singh
Dies ist besser als der unten stehende Ansatz "SHOW COLUMNS", der in parametrisierten Abfragen verwendet werden kann, um das Risiko einer SQL-Injection zu verringern. Sie wollten nur hinzufügen, dass Sie die Funktion TABLE_SCHEMA mit der Funktion DATABASE () füllen können.
Andrew
16

Versuchen Sie etwas wie, um jedem zu helfen, der nach einem konkreten Beispiel für die Beschreibung von @Mchl sucht

SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'

Wenn false zurückgegeben wird (keine Ergebnisse), wissen Sie, dass die Spalte nicht vorhanden ist.

julio
quelle
2
Ich glaube, es sollte sein TABLE_NAME = 'my_table', TABLE_SCHEMA ist das Schema, in dem sich die Tabelle befindet. SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
Dh
10

Das Folgende ist eine andere Möglichkeit, dies mit einfachem PHP ohne die Datenbank information_schema zu tun:

$chkcol = mysql_query("SELECT * FROM `my_table_name` LIMIT 1");
$mycol = mysql_fetch_array($chkcol);
if(!isset($mycol['my_new_column']))
  mysql_query("ALTER TABLE `my_table_name` ADD `my_new_column` BOOL NOT NULL DEFAULT '0'");
wvasconcelos
quelle
Warum sollten Sie die Verwendung von information_schema vermeiden? Es existiert nur zu diesem Zweck. (Auch dieser Thread ist ziemlich alt und wurde bereits beantwortet.)
Leigh
1
In meinen Tests ist dies ungefähr 10-50x schneller als bei Verwendung von information_schema. Es ist erforderlich, dass die Tabelle mindestens eine Zeile enthält, was Sie nicht immer garantieren können.
Martijn
isset()würde 'false' auslösen, wenn der Array-Schlüssel vorhanden ist, der Wert jedoch NULL ist . Es ist besser, array_key_exists()wie zu verwendenif( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler
1
Diese Antwort machte mich facepalm, weil ich einen einfachen isset()Scheck übersah . Es löst die Frage nicht, aber es ist besser, wenn Sie die Auswahlabfrage bereits ausführen müssen und das Ergebnis im Speicher haben.
Siphon
10

Ich habe diese gespeicherte Prozedur zusammen mit einem Anfang von @ lains obigen Kommentaren geworfen, ein bisschen nett, wenn Sie sie mehr als ein paar Mal aufrufen müssen (und kein PHP benötigen):

delimiter //
-- ------------------------------------------------------------
-- Use the inforamtion_schema to tell if a field exists.
-- Optional param dbName, defaults to current database
-- ------------------------------------------------------------
CREATE PROCEDURE fieldExists (
OUT _exists BOOLEAN,      -- return value
IN tableName CHAR(255),   -- name of table to look for
IN columnName CHAR(255),  -- name of column to look for
IN dbName CHAR(255)       -- optional specific db
) BEGIN
-- try to lookup db if none provided
SET @_dbName := IF(dbName IS NULL, database(), dbName);

IF CHAR_LENGTH(@_dbName) = 0
THEN -- no specific or current db to check against
  SELECT FALSE INTO _exists;
ELSE -- we have a db to work with
  SELECT IF(count(*) > 0, TRUE, FALSE) INTO _exists
  FROM information_schema.COLUMNS c
  WHERE 
  c.TABLE_SCHEMA    = @_dbName
  AND c.TABLE_NAME  = tableName
  AND c.COLUMN_NAME = columnName;
END IF;
END //
delimiter ;

Arbeiten mit fieldExists

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_option', NULL) //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

mysql> call fieldExists(@_exists, 'jos_vm_product', 'child_options', 'etrophies') //
Query OK, 0 rows affected (0.01 sec)

mysql> select @_exists //
+----------+
| @_exists |
+----------+
|        1 |
+----------+
Quickshiftin
quelle
MIster @quickshiftin, vielen Dank. Dies hilft mir zu überprüfen, ob eine Tabelle ablaufbar ist , indem ich überprüfe , ob ein ExpirationDateFeld vorhanden ist. 😊
Jeancarlo Fontalvo
@ JeancarloFontalvo Es ist mir ein Vergnügen! Überprüfen Sie auch mein MySQL-Inspektoren-Projekt, das ich gestartet habe, um das Schema mit übergeordneten Methoden zu überprüfen .
Quickshiftin
1
OMG Es ist wie in einer Bibliothek 😱. Danke, dass du es geteilt hast, Mister!
Jeancarlo Fontalvo
8

Wählen Sie nur Spaltenname aus dem Informationsschema aus und fügen Sie das Ergebnis dieser Abfrage in eine Variable ein. Testen Sie dann die Variable, um zu entscheiden, ob die Tabelle geändert werden muss oder nicht.

PS Beschlagen Sie nicht, TABLE_SCHEMA auch für die Tabelle COLUMNS anzugeben.

Mchl
quelle
1
Ich bin ziemlich neu in MySQL. Können Sie hier vielleicht ein kleines Beispiel posten?
Clops
2

Ich benutze dieses einfache Skript:

mysql_query("select $column from $table") or mysql_query("alter table $table add $column varchar (20)");

Es funktioniert, wenn Sie bereits mit der Datenbank verbunden sind.

vio
quelle
Dies würde nur funktionieren, wenn die Tabelle auch Datenzeilen enthält. Aber wenn der Tisch leer wäre, würde das nicht funktionieren.
Orrd
1
nicht perfekt, verwendet alte Treiber, funktioniert nicht, wenn die Tabelle leer ist, Eingaben nicht maskiert, aber ich mag, wie Sie es in einer Zeile gemacht haben. +1
Ich habe einmal mit einem Bären gerungen.
1

Vielen Dank an Mfoo, der das wirklich schöne Skript zum dynamischen Hinzufügen von Spalten erstellt hat, wenn es nicht in der Tabelle vorhanden ist. Ich habe seine Antwort mit PHP verbessert . Das Skript hilft Ihnen außerdem dabei, herauszufinden, wie viele Tabellen tatsächlich den MySQL - Befehl 'Spalte hinzufügen ' benötigen. Probieren Sie einfach das Rezept. Funktioniert wie Charme.

<?php
ini_set('max_execution_time', 0);

$host = 'localhost';
$username = 'root';
$password = '';
$database = 'books';

$con = mysqli_connect($host, $username, $password);
if(!$con) { echo "Cannot connect to the database ";die();}
mysqli_select_db($con, $database);
$result=mysqli_query($con, 'show tables');
$tableArray = array();
while($tables = mysqli_fetch_row($result)) 
{
     $tableArray[] = $tables[0];    
}

$already = 0;
$new = 0;
for($rs = 0; $rs < count($tableArray); $rs++)
{
    $exists = FALSE;

    $result = mysqli_query($con, "SHOW COLUMNS FROM ".$tableArray[$rs]." LIKE 'tags'");
    $exists = (mysqli_num_rows($result))?TRUE:FALSE;

    if($exists == FALSE)
    {
        mysqli_query($con, "ALTER TABLE ".$tableArray[$rs]." ADD COLUMN tags VARCHAR(500) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL");
        ++$new;
        echo '#'.$new.' Table DONE!<br/>';
    }
    else
    {
        ++$already;
        echo '#'.$already.' Field defined alrady!<br/>';    
    }
    echo '<br/>';
}
?>
Webblover
quelle
1

Diese Arbeit für mich mit Beispiel PDO:

public function GetTableColumn() {      
$query  = $this->db->prepare("SHOW COLUMNS FROM `what_table` LIKE 'what_column'");  
try{            
    $query->execute();                                          
    if($query->fetchColumn()) { return 1; }else{ return 0; }
    }catch(PDOException $e){die($e->getMessage());}     
}
user3706926
quelle
0

Setzen Sie ALTER TABLE / MODIFY COLS oder andere solche Table Mod-Operationen NICHT in eine TRANSACTION ein. Transaktionen dienen dazu, einen QUERY-Fehler zurückzusetzen, nicht für ÄNDERUNGEN. Er tritt jedes Mal in einer Transaktion auf.

Führen Sie einfach eine SELECT * -Abfrage für die Tabelle aus und prüfen Sie, ob die Spalte vorhanden ist ...

gmize
quelle
ALTER(und DDL so) in MySQL tatsächlich die Transaktion (implizit) festschreiben. Die Verwendung von SELECT * würde jedoch einen großen Overhead im Netzwerk erzeugen, wenn nur die Existenz der Spalte überprüft wird. Sie könnten stattdessen versuchen SELECT my_col_to_check FROM t LIMIT 0: Wenn MySQL einen Fehler generiert, ist die Spalte wahrscheinlich nicht vorhanden (überprüfen Sie den Fehler dennoch, da es sich möglicherweise um ein Netzwerkproblem handelt oder was auch immer!). Wenn kein Fehler generiert wird, ist eine Spalte vorhanden. Ich bin mir nicht sicher, ob dies der beste Weg ist, um die Spaltenexistenz zu überprüfen.
Xenos