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?



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;

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!


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.


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

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

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.


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.


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

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

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 ...


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.