MySQL, sprawdź, czy kolumna istnieje w tabeli z SQL

135

Próbuję napisać zapytanie, które sprawdzi, czy dana tabela w MySQL ma określoną kolumnę, a jeśli nie - utwórz ją. W przeciwnym razie nic nie rób. Jest to naprawdę łatwa procedura w każdej bazie danych klasy korporacyjnej, ale MySQL wydaje się być wyjątkiem.

Pomyślałem o czymś takim

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;

zadziała, ale bardzo zawodzi. Czy istnieje sposób?

clops
źródło
Dlaczego po prostu go nie stworzyć? Jeśli istnieje, tworzenie się nie powiedzie, ale nie obchodzi cię to.
Brian Hooper
tworzenie odbywa się wewnątrz transakcji, a niepowodzenie zakończy całą transakcję, smutne, ale prawdziwe
klika
@haim - dzięki za headups, ale zapytanie sugerowane w twoim linku działa tylko wewnątrz procedury :(
clops
2
Instrukcje DDL powodują niejawne zatwierdzenie w bieżącej transakcji. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

Odpowiedzi:

271

To działa dobrze dla mnie.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

Z PHP byłoby to coś w rodzaju ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Mfoo
źródło
11
Pytanie nie brzmi, jak to zrobić za pomocą php + sql lub java + sql, ale jak to zrobić używając czystego sql / mysql, stąd głos przeciwny
Yuriy Nakonechnyy
64
Odpowiadasz na pytanie + kilka informacji, które pomogły mi i prawdopodobnie innym, +1
Francisco Presencia
@Mfoo Dzięki Mfoo, uratowałeś mi dzień! Działa jak urok. Jedno z najlepszych rozwiązań poza tworzeniem Procedur do tego zadania.
webblover
9
Yura: Czysta odpowiedź SQL / MySQL to pierwsza część, w której mówi: „POKAŻ KOLUMNY Z tabeli LIKE 'nazwa pola'”. Możesz zignorować kod PHP, to tylko przykład jednego ze sposobów na pobranie i zinterpretowanie wyniku, jeśli używasz PHP.
orrd
1
@codenamezero Zakładam, że masz na myśli używanie MSSQL, to pytanie dotyczyło MySQL. odnieś się do tego posta dla MSSQL
Mfoo
160

@julio

Dzięki za przykład SQL. Wypróbowałem zapytanie i myślę, że wymaga niewielkiej zmiany, aby działało poprawnie.

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

To zadziałało dla mnie.

Dzięki!

Iain
źródło
Z moich ograniczonych badań wynika, że ​​nie wszystkie środowiska hostingowe mają bazę danych information_schema. Wszystkie środowiska cpanel, z których korzystałem, mają to. To dostarczone rozwiązanie zależy od istniejącej bazy danych.
cardi777
2
Ta odpowiedź jest lepsza niż użycie „POKAŻ KOLUMNY”, ponieważ używa standardowego sposobu ANSI do pobierania informacji z tabeli, w przeciwieństwie do POKAŻ KOLUMNY, które jest specyficzne dla MySQL. Więc to rozwiązanie będzie działać z innymi bazami danych. Używanie „schematu_informacyjnego” brzmi dziwnie i można by pomyśleć, że nie byłby to standardowy sposób SQL, ale tak jest.
orrd
5
Zwróć uwagę, że ta odpowiedź zawiera tylko informacje o istnieniu kolumny. Jeśli chcesz warunkowo wykonać niektóre instrukcje DDL, będziesz musiał zawinąć całość w procedurę, która zezwala na takie instrukcje IFitp. Zobacz stackoverflow.com/questions/7384711/ ... aby zapoznać się z przykładem zawijania procedury wokół test dla kolumny i warunkowej instrukcji DML.
Christopher Schultz
@Iain: stackoverflow.com/questions/32962149/ ... Odniosłem się do twojej odpowiedzi
Amar Singh
Jest to lepsze rozwiązanie niż poniższe podejście „POKAŻ KOLUMNY”, ponieważ może być używane w zapytaniach parametrycznych, które zmniejszają ryzyko wstrzyknięcia kodu SQL. Chciałem tylko dodać, że możesz użyć funkcji DATABASE () do zapełnienia kolumny TABLE_SCHEMA.
Andrew,
16

Aby pomóc każdemu, kto szuka konkretnego przykładu tego, co opisywał @Mchl, spróbuj czegoś takiego

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

Jeśli zwróci fałsz (zero wyników), wiesz, że kolumna nie istnieje.

julio
źródło
2
Myślę, że tak powinno być TABLE_NAME = 'my_table', TABLE_SCHEMA to schemat, w którym znajduje się stół. Tj.SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
AaronHolland.
11

Wrzuciłem tę procedurę składowaną razem z początkiem z komentarzy @ lain powyżej, trochę fajnie, jeśli musisz wywołać ją więcej niż kilka razy (i nie potrzebujesz 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 ;

Praca z 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
źródło
MIster @quickshiftin, bardzo dziękuję. Pomaga mi to sprawdzić, czy tabela jest pożądana , sprawdzając, czy ma ExpirationDatepole. 😊
Jeancarlo Fontalvo
@JeancarloFontalvo Z przyjemnością! Sprawdź także mój projekt mysql-inspectors, który zacząłem w celu sprawdzenia schematu metodami wyższego poziomu.
quickshift w
1
OMG To jak biblioteka 😱. Dzięki za udostępnienie go Panu!
Jeancarlo Fontalvo
10

Poniżej znajduje się inny sposób na zrobienie tego przy użyciu zwykłego PHP bez bazy danych 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'");
wvasconcelos
źródło
Dlaczego nie chcesz używać schematu information_schema? Istnieje tylko w tym celu. (Również ten wątek jest dość stary i został już odebrany.)
Leigh
1
W moich testach jest to około 10-50 razy szybsze niż przy użyciu schematu information_schema. Wymaga to, aby tabela miała co najmniej jeden wiersz, czego nie zawsze możesz zagwarantować.
Martijn
isset()spowodowałoby wyświetlenie „false”, jeśli klucz tablicy istnieje, ale ma wartość NULL . Lepiej użyć array_key_exists()if( !array_key_exists( 'my_new_column', $mycol ) )
czegoś
1
Ta odpowiedź zmusiła mnie do zastanowienia się, ponieważ przeoczyłem prostą isset()kontrolę. To nie rozwiązuje pytania, ale lepiej jest, jeśli już musisz wykonać zapytanie wybierające i mieć wynik w pamięci.
Syfon
8

Wybierz tylko nazwę_kolumny ze schematu informacyjnego i umieść wynik tego zapytania w zmiennej. Następnie przetestuj zmienną, aby zdecydować, czy tabela wymaga zmiany, czy nie.

PS Nie męcz się, aby określić TABLE_SCHEMA również dla tabeli COLUMNS.

Mchl
źródło
1
Jestem raczej nowy w MySQL, czy możesz zamieścić tutaj mały przykład?
kleszcze
2

Używam tego prostego skryptu:

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

Działa, jeśli jesteś już połączony z bazą danych.

vio
źródło
To zadziałałoby tylko wtedy, gdyby zdarzyło się, że tabela zawiera również wiersze danych. Ale gdyby stół był pusty, to nie zadziałałoby.
orrd
1
nie jest doskonały, używa starych sterowników, nie działa, jeśli tabela jest pusta, dane wejściowe nie uciekły, ale podoba mi się, jak to zrobiłeś w jednej linii. +1
Raz walczyłem z niedźwiedziem.
1

Wielkie dzięki dla Mfoo, który umieścił naprawdę fajny skrypt do dynamicznego dodawania kolumn, jeśli nie ma ich w tabeli. Poprawiłem jego odpowiedź za pomocą PHP . Skrypt dodatkowo pomaga znaleźć ile rzeczywiście potrzebne tabele kolumny „” Dodaj mysql COMAND. Po prostu posmakuj przepisu. Działa jak urok.

<?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
źródło
1

Ta praca dla mnie z przykładowym 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
źródło
0

NIE WKŁADAJ ALTER TABLE / MODIFY COLS ani żadnych innych takich operacji modów tabeli wewnątrz TRANSAKCJI. Transakcje są po to, aby móc wycofać błąd QUERY, a nie ALTERations ... będzie to błąd za każdym razem w transakcji.

Po prostu uruchom zapytanie SELECT * na tabeli i sprawdź, czy kolumna jest tam ...

gmize
źródło
ALTER(i tego typu DDL) w MySQL rzeczywiście zatwierdza (niejawnie) transakcję. Ale użycie polecenia SELECT * spowodowałoby duże obciążenie sieci związane z samym sprawdzaniem istnienia kolumny. Zamiast tego możesz spróbować SELECT my_col_to_check FROM t LIMIT 0: jeśli mysql generuje błąd, kolumna prawdopodobnie nie istnieje (nadal sprawdź błąd, ponieważ może to być problem z siecią lub cokolwiek!); jeśli nie generuje błędu, kolumna istnieje. Nie jestem pewien, czy to najlepszy sposób na sprawdzenie istnienia kolumny.
Xenos