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;

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



Почему бы просто не создать его? Если он существует, создание не удастся, но вам все равно.
Брайан Хупер,

создание происходит внутри транзакции, и сбой завершит всю транзакцию, грустно, но факт
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;

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'

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

Спасибо!


Из моих ограниченных исследований видно, что не во всех средах хостинга есть база данных 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 (нулевые результаты), значит, столбец не существует.


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

Почему бы вам избежать использования 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 |
+----------+

MIster @quickshiftin, большое вам спасибо. Это помогает мне проверить, не истек ли срок действия таблицы , проверив , есть ли у нее ExpirationDateполе. 😊
Жанкарло Фонтальво 03

@JeancarloFontalvo С удовольствием! Также ознакомьтесь с моим проектом mysql-Inspectors, который я начал для проверки схемы с помощью методов более высокого уровня.
quickshiftin

1
OMG Это как библиотека 😱. Спасибо, что поделились этим, мистер!
Жанкарло Фонтальво 03

8

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

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


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

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

0

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

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


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