MySQL, controlla se esiste una colonna in una tabella con SQL


130

Sto cercando di scrivere una query che controllerà se una tabella specifica in MySQL ha una colonna specifica e, in caso contrario, crearla. Altrimenti non fare nulla. Questa è davvero una procedura semplice in qualsiasi database di classe enterprise, ma MySQL sembra essere un'eccezione.

Ho pensato a qualcosa del genere

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;

funzionerebbe, ma fallisce male. C'è un modo?



Perché non semplicemente crearlo? Se esiste, la creazione fallirà ma non ti interessa.
Brian Hooper,

la creazione avviene all'interno di una transazione e il fallimento interromperà l'intera transazione, triste ma vero
interrompe il

@haim - grazie per gli headup, ma la query suggerita nel tuo link funziona solo all'interno di una procedura :(
clops

2
Le istruzioni DDL causano il commit implicito nella transazione corrente. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

Risposte:


259

Questo funziona bene per me.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Con PHP sarebbe qualcosa come ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;

8
La domanda non è come farlo usando php + sql o java + sql, è come farlo usando pure sql / mysql da qui il downvote
Yuriy Nakonechnyy

61
Rispondi alla domanda + alcune informazioni che hanno aiutato me e probabilmente altri, +1
Francisco Presencia,

@Mfoo Grazie Mfoo, mi hai salvato la giornata! Funziona come il fascino. Una delle migliori soluzioni oltre alla creazione di procedure per questo compito.
webblover

8
Yura: La pura risposta SQL / MySQL è la prima parte in cui dice che usa "MOSTRA COLONNE DA TAVOLA COME 'fieldname'". Puoi ignorare il codice PHP, questo è solo un esempio di un modo per recuperare e interpretare il risultato se ti capita di usare PHP.
or

1
@codenamezero Presumo che ti riferisca all'utilizzo di MSSQL, questa domanda riguardava MySQL. fare riferimento a questo post per MSSQL
Mfoo il

158

@julio

Grazie per l'esempio SQL. Ho provato la query e penso che abbia bisogno di una piccola modifica per farlo funzionare correttamente.

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

Questo ha funzionato per me.

Grazie!


Dalla mia ricerca limitata risulta che non tutti gli ambienti di hosting dispongono di un database information_schema. Tutti gli ambienti cpanel che ho usato ce l'hanno. Questa soluzione fornita dipende da questo DB esistente.
cardi777,

2
Questa risposta è migliore dell'uso di "SHOW COLUMNS" perché utilizza il modo standard ANSI per ottenere informazioni sulla tabella, a differenza di SHOW COLUMNS che è specifico di MySQL. Quindi questa soluzione funzionerà con altri database. L'uso di "information_schema" suona strano e penseresti che non sarebbe il modo SQL standard per farlo, ma lo è.
or

5
Nota che questa risposta ti fornisce solo le informazioni sull'esistenza della colonna. Se si desidera eseguire in modo condizionale alcune istruzioni DDL, è necessario racchiudere il tutto in una procedura che consenta istruzioni come IF, ecc. Vedere stackoverflow.com/questions/7384711/… per un esempio di come concludere una procedura il test per la colonna e l'istruzione DML condizionale.
Christopher Schultz,

@Iain: stackoverflow.com/questions/32962149/... Ho refered la tua risposta
Amar Singh

Questo è migliore dell'approccio "MOSTRA COLONNE" di seguito, poiché può essere utilizzato nelle query con parametri che riducono il rischio di iniezione SQL. Volevo solo aggiungere che puoi usare la funzione DATABASE () per popolare la colonna TABLE_SCHEMA.
Andrew,

16

Solo per aiutare chiunque cerchi un esempio concreto di ciò che @Mchl stava descrivendo, prova qualcosa del genere

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

Se restituisce false (zero risultati), sai che la colonna non esiste.


2
Credo che dovrebbe essere TABLE_NAME = 'my_table', TABLE_SCHEMA è lo schema in cui si trova la tabella. SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
Vale a

10

Di seguito è riportato un altro modo per farlo utilizzando il semplice PHP senza il database information_schema:

$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'");

Perché dovresti evitare di usare information_schema? Esiste solo per questo scopo. (Inoltre, questa discussione è piuttosto vecchia e ha già ricevuto risposta.)
Leigh

1
Nei miei test, questo è circa 10-50 volte più veloce rispetto all'utilizzo di information_schema. Richiede che la tabella abbia almeno una riga, cosa che non si può sempre garantire.
Martijn,

isset()trow 'false' se esiste la chiave dell'array ma il valore è NULL . È meglio usare array_key_exists()comeif( !array_key_exists( 'my_new_column', $mycol ) )
Paul Geisler il

1
Questa risposta mi ha reso facepalm perché ho trascurato un semplice isset()controllo. Non risolve la domanda, ma è meglio se è già necessario eseguire la query di selezione e avere il risultato in memoria.
Sifone

10

Ho lanciato questa procedura memorizzata insieme a un inizio dai commenti di @ lain sopra, un po 'bello se hai bisogno di chiamarlo più di un paio di volte (e non hai bisogno di php):

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 ;

Lavorando con 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 |
+----------+

Grazie @quickshiftin, grazie mille. Questo mi aiuta a verificare se una tabella è conveniente , controllando se ha un ExpirationDatecampo. 😊
Jeancarlo Fontalvo,

@JeancarloFontalvo Piacere mio! Dai un'occhiata anche al mio progetto mysql-inspector che ho iniziato per ispezionare lo schema con metodi di livello superiore.
cambio rapido

1
OMG È come una biblioteca 😱. Grazie per averlo condiviso, signore!
Jeancarlo Fontalvo,

8

Selezionare solo nome_colonna dallo schema delle informazioni e inserire il risultato di questa query in una variabile. Quindi testare la variabile per decidere se la tabella deve essere modificata o meno.

PS Non dimenticare di specificare TABLE_SCHEMA anche per la tabella COLUMNS.


1
Sono piuttosto nuovo su MySQL, puoi forse pubblicare un piccolo esempio qui?
chiude il

2

Sto usando questo semplice script:

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

Funziona se sei già connesso al database.


Ciò funzionerebbe solo se la tabella contenesse anche righe di dati. Ma se il tavolo fosse vuoto, questo non funzionerebbe.
or

1
non perfetto, usa vecchi driver, non funziona se la tabella è vuota, input non sfuggiti, ma mi piace come l'hai fatto in una riga. +1
Ho lottato con un orso una volta.

1

Mille grazie a Mfoo che ha messo lo script davvero carino per l'aggiunta dinamica di colonne se non esiste nella tabella. Ho migliorato la sua risposta con PHP . Lo script ti aiuta inoltre a trovare quante tabelle effettivamente necessitavano del comando mysql 'Aggiungi colonna' . Assaggia la ricetta. Funziona come il fascino.

<?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/>';
}
?>

1

Questo lavoro per me con il campione DOP:

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());}     
}

0

NON inserire ALTER TABLE / MODIFY COLS o qualsiasi altra operazione di modifica tabella all'interno di una TRANSAZIONE. Le transazioni sono per essere in grado di ripristinare un errore QUERY non per ALTERATION ... verrà fuori ogni volta in una transazione.

Basta eseguire una query SELECT * sulla tabella e verificare se la colonna è presente ...


ALTER(e DDL così) in MySQL effettivamente commettono (implicitamente) la transazione. Ma l'uso di SELECT * genererebbe un grande sovraccarico in rete per il solo controllo dell'esistenza della colonna. Potresti invece provare SELECT my_col_to_check FROM t LIMIT 0: se mysql genera un errore, probabilmente la colonna non esiste (ancora, controlla l'errore, poiché potrebbe essere un problema di rete o altro!); se non genera alcun errore, allora esiste una colonna. Non sono sicuro che sia il modo migliore per verificare l'esistenza di colonne.
Xenos,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.