MySQL, проверьте, существует ли столбец в таблице с SQL

130

Я пытаюсь написать запрос, который будет проверять, есть ли в конкретной таблице в MySQL определенный столбец, а если нет - создать его. Иначе ничего не делать. Это действительно простая процедура в любой базе данных корпоративного класса, но MySQL кажется исключением.

Я думал что-то вроде

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;

будет работать, но это плохо. Есть способ?

clops
источник
Почему бы просто не создать его? Если он существует, создание не удастся, но вам все равно.
Брайан Хупер,
создание происходит внутри транзакции, и сбой завершит всю транзакцию, грустно, но факт
2010 г.,
@haim - это для заголовков, но запрос, предложенный в вашей ссылке, работает только внутри процедуры :(
clops
2
Операторы DDL вызывают неявную фиксацию в текущей транзакции. dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl 03

Ответы:

260

У меня это хорошо работает.

SHOW COLUMNS FROM `table` LIKE 'fieldname';

С PHP это было бы что-то вроде ...

$result = mysql_query("SHOW COLUMNS FROM `table` LIKE 'fieldname'");
$exists = (mysql_num_rows($result))?TRUE:FALSE;
Mfoo
источник
9
Вопрос не в том, как это сделать с помощью php + sql или java + sql, а в том, как это сделать с помощью чистого sql / mysql, отсюда и отрицательный голос
Юрий Наконечный
62
Вы отвечаете на вопрос + некоторая информация, которая помогла мне и, вероятно, другим, +1
Francisco Presencia
@Mfoo Спасибо, Mfoo, ты спас мне день! Работает как шарм. Одно из лучших решений помимо создания процедур для этой задачи.
webblover
8
Юра: Чистый ответ SQL / MySQL - это первая часть, в которой он говорит, что нужно использовать «ПОКАЗАТЬ КОЛОНКИ ИЗ таблицы LIKE 'fieldname'». Вы можете не обращать внимания на код PHP, это всего лишь пример одного из способов получить и интерпретировать результат, если вы используете PHP.
orrd
1
@codenamezero Я предполагаю, что вы имеете в виду использование MSSQL, этот вопрос касался MySQL. обратитесь к этому сообщению для MSSQL
Mfoo
158

@julio

Спасибо за пример SQL. Я попробовал запрос и считаю, что для правильной работы требуется небольшое изменение.

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

Это сработало для меня.

Спасибо!

Iain
источник
Из моих ограниченных исследований видно, что не во всех средах хостинга есть база данных information_schema. Он есть во всех средах cpanel, которые я использовал. Это предоставленное решение зависит от существующей БД.
cardi777
2
Этот ответ лучше, чем использование SHOW COLUMNS, потому что он использует стандартный способ ANSI для получения информации о таблицах, в отличие от SHOW COLUMNS, специфичного для MySQL. Таким образом, это решение будет работать с другими базами данных. Использование «information_schema» звучит странно, и вы могли бы подумать, что это не стандартный способ SQL, но это так.
orrd
5
Обратите внимание, что этот ответ дает вам только информацию о существовании столбца. Если вы хотите условно выполнить некоторые операторы DDL, вам придется обернуть все это в процедуру, которая допускает такие операторы, как IFи т.д. См. Stackoverflow.com/questions/7384711/… для примера того, как обернуть процедуру вокруг тест для столбца и условного оператора DML.
Christopher Schultz
@Iain: stackoverflow.com/questions/32962149/… Я сослался на ваш ответ
Амар Сингх
Это лучше, чем подход «SHOW COLUMNS», описанный ниже, так как его можно использовать в параметризованных запросах, снижая риск внедрения SQL. Просто хотел добавить, вы можете использовать функцию DATABASE () для заполнения столбца TABLE_SCHEMA.
Эндрю
16

Чтобы помочь любому, кто ищет конкретный пример того, что описывал @Mchl, попробуйте что-нибудь вроде

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

Если он возвращает false (нулевые результаты), значит, столбец не существует.

Julio
источник
2
Я считаю, что так и должно быть TABLE_NAME = 'my_table', TABLE_SCHEMA - это схема, в которой находится таблица. Т.е.SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'my_schema' AND TABLE_NAME = 'my_table' AND COLUMN_NAME = 'my_column'
AaronHolland
10

Ниже приведен еще один способ сделать это с использованием простого PHP без базы данных 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
источник
Почему бы вам избежать использования information_schema? Он существует как раз для этой цели. (Кроме того, эта ветка довольно старая, и
Leigh
1
В моих тестах это примерно в 10-50 раз быстрее, чем при использовании information_schema. Это действительно требует, чтобы таблица имела хотя бы одну строку, что не всегда можно гарантировать.
Martijn
isset()будет иметь значение «false», если ключ массива существует, но значение NULL . Лучше использовать array_key_exists()лайкif( !array_key_exists( 'my_new_column', $mycol ) )
Пол Гейслер
1
Этот ответ вызвал у меня фейспалм, потому что я упустил простую isset()проверку. Это не решает вопрос, но лучше, если вам уже нужно выполнить запрос выбора и получить результат в памяти.
Siphon
10

Я добавил эту хранимую процедуру вместе с началом из комментариев @lain выше, что неплохо, если вам нужно вызывать ее более нескольких раз (и не требует 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 ;

Работаю с 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
источник
MIster @quickshiftin, большое вам спасибо. Это помогает мне проверить, не истек ли срок действия таблицы , проверив , есть ли у нее ExpirationDateполе. 😊
Жанкарло Фонтальво 03
@JeancarloFontalvo С удовольствием! Также ознакомьтесь с моим проектом mysql-Inspectors, который я начал для проверки схемы с помощью методов более высокого уровня.
quickshiftin
1
OMG Это как библиотека 😱. Спасибо, что поделились этим, мистер!
Жанкарло Фонтальво 03
8

Выберите только имя_столбца из информационной схемы и поместите результат этого запроса в переменную. Затем проверьте переменную, чтобы решить, нуждается ли таблица в изменении или нет.

PS Не забудьте указать TABLE_SCHEMA и для таблицы COLUMNS.

MCHL
источник
1
Я новичок в MySQL, не могли бы вы опубликовать здесь небольшой пример?
закрытие 03
2

Я использую этот простой скрипт:

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

Это работает, если вы уже подключены к базе данных.

ВИО
источник
Это будет работать только в том случае, если в таблице также есть строки данных. Но если бы стол был пуст, это не сработало бы.
orrd
1
не идеально, использует старые драйверы, не работает, если таблица пуста, вводы не экранированы, но мне нравится, как вы сделали это в одну строку. +1
Однажды я боролся с медведем.
1

Большое спасибо Mfoo, который разместил действительно хороший скрипт для динамического добавления столбцов, если их нет в таблице. Я улучшил его ответ с помощью PHP . Сценарий дополнительно поможет найти сколько таблиц на самом деле необходимый «Добавить столбец» MySQL COMAND. Просто попробуйте рецепт. Работает как шарм.

<?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
источник
1

Эта работа для меня с образцом 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
источник
0

ЗАПРЕЩАЕТСЯ помещать ALTER TABLE / MODIFY COLS или любые другие подобные операции с модификациями таблиц в ТРАНЗАКЦИЮ. Транзакции предназначены для возможности откатить сбой QUERY, а не для ИЗМЕНЕНИЙ ... он будет ошибаться каждый раз в транзакции.

Просто запустите запрос SELECT * к таблице и проверьте, есть ли там столбец ...

gmize
источник
ALTER(и подобный DDL) в MySQL действительно фиксирует (неявно) транзакцию. Но использование SELECT * приведет к большим накладным расходам в сети из-за простой проверки существования столбца. Вместо этого вы можете попробовать SELECT my_col_to_check FROM t LIMIT 0: если mysql генерирует ошибку, вероятно, столбец не существует (тем не менее, проверьте ошибку, так как это может быть проблема с сетью или что-то еще!); если ошибки нет, значит столбец существует. Я не уверен, что это лучший способ проверить наличие столбца.
Xenos