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;

動作しますが、それはひどく失敗します。方法はありますか?



なぜそれを作成しないのですか?存在する場合、作成は失敗しますが、気にする必要はありません。
Brian Hooper、

作成は、トランザクション内で行われ、障害が全体のトランザクションを終了します、悲しいが、真
clops

@haim —ヘッドアップに感謝しますが、リンクで提案されたクエリはプロシージャ内でのみ機能します:(
clops

2
DDLステートメントは、現在のトランザクションで暗黙的なコミットを引き起こします。dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
Mchl

回答:


259

これは私にとってはうまくいきます。

SHOW COLUMNS FROM `table` LIKE 'fieldname';

PHPでは、次のようになります...

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

8
問題は、php + sqlまたはjava + sqlを使用してそれを行う方法ではなく、純粋なsql / mysqlを使用してそれを行う方法です。つまり、反対投票
Yuriy Nakonechnyy

61
あなたは質問に答え、私とおそらく他の人を助けたいくつかの情報、+ 1
Francisco Presencia

@Mfoo Mfooありがとう、あなたは私の日を救った!魅力のように機能します。このタスクのプロシージャを作成する以外の最良のソリューションの1つ。
webblover

8
由良:純粋なSQL / MySQLの答えは、 "SHOW COLUMNS FROM table LIKE 'fieldname'"を使用するという最初の部分です。PHPコードを無視できます。これは、PHPを使用している場合に結果を取得して解釈する1つの方法の例にすぎません。
2014年

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 DBがあるわけではないようです。私が使用したすべてのcpanel環境にはそれがあります。この提供されるソリューションは、このDBが存在するかどうかに依存します。
cardi777 2014年

2
この回答は、「SHOW COLUMNS」を使用するよりも優れています。これは、MySQLに固有のSHOW COLUMNSとは異なり、ANSI標準の方法を使用してテーブル情報を取得するためです。したがって、このソリューションは他のデータベースでも機能します。「information_schema」の使用は奇妙に聞こえ、これを行う標準のSQLの方法ではないように思われるかもしれませんが、そうではありません。
2014年

5
この回答は、列の存在に関する情報のみを取得することに注意してください。一部のDDLステートメントを条件付きで実行する場合は、全体をIFなどのステートメントを許可するプロシージャでラップする必要があります。プロシージャをラップする方法の例については、stackoverflow.com / questions / 7384711 /…を参照してください列と条件付きDMLステートメントのテスト。
クリストファーシュルツ2014

@Iain:stackoverflow.com/questions/32962149/…私はあなたの答えを参照しました
Amar Singh

これは、SQLインジェクションのリスクを軽減するパラメーター化されたクエリで使用できるため、以下の「SHOW COLUMNS」アプローチよりも優れています。追加したいのは、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

以下は、information_schemaデータベースなしでプレーンなPHPを使用して行う別の方法です。

$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の使用を避けたいのはなぜですか?それはこの目的のためだけに存在しています。(また、このスレッドはかなり古く、既に回答されています。)
リー

1
私のテストでは、これはinformation_schemaを使用するよりも約10〜50倍高速です。テーブルには少なくとも1つの行が必要ですが、これは常に保証できるわけではありません。
Martijn 2013年

isset()配列キーは存在するが値がNULLの場合は、「false」をスローします。次のarray_key_exists()ように使用することをお勧めしますif( !array_key_exists( 'my_new_column', $mycol ) )
ポールガイスラー2016年

1
私は簡単なisset()チェックを見落としたので、この答えは私をfacepalmにしました。これは問題を解決しませんが、selectクエリを実行して結果をメモリに格納する必要がある場合に適しています。
サイフォン

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、フィールドを。😊
Jeancarlo Fontalvo

@JeancarloFontalvoどういたしまして!また、より高レベルのメソッドでスキーマを検査するために始めたmysql-inspectorsプロジェクトも確認してください。
quickshiftin 2017

1
OMGそれは図書館のようなものです😱。共有してくれてありがとうミスター!
Jeancarlo Fontalvo 2017

8

情報スキーマからcolumn_nameのみを選択し、このクエリの結果を変数に入れます。次に、変数をテストして、テーブルを変更する必要があるかどうかを判断します。

PS COLUMNSテーブルにもTABLE_SCHEMAを指定することを忘れないでください。


1
私はMySQLにかなり慣れていませんが、ここに小さな例を投稿できますか?
クロップ

2

私はこの簡単なスクリプトを使用しています:

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

すでにデータベースに接続している場合に機能します。


これは、テーブルにもたまたまデータ行がある場合にのみ機能します。しかし、テーブルが空の場合、これは機能しません。
2014年

1
完全ではなく、古いドライバーを使用し、テーブルが空の場合は機能せず、入力はエスケープされませんが、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

TRANSACTION内にALTER TABLE / MODIFY COLSまたは他のそのようなテーブルmod操作を配置しないでください。トランザクションは、ALTERATIONSではなく、QUERYの失敗をロールバックできるようにするためのものです。トランザクションでは毎回エラーになります。

テーブルでSELECT *クエリを実行して、列が存在するかどうかを確認するだけです...


ALTER(そしてDDLのような)MySQLでは実際にトランザクションを(暗黙的に)コミットします。しかし、SELECT *を使用すると、列の存在を確認するだけでネットワークに大きなオーバーヘッドが発生します。代わりに試してみてくださいSELECT my_col_to_check FROM t LIMIT 0:mysqlがエラーを生成する場合、列はおそらく存在しません(ネットワークの問題などである可能性があるため、エラーを確認してください)。エラーが発生しない場合は、列が存在します。列の存在を確認するための最良の方法であるかどうかはわかりません。
Xenosの
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.