114

私の研究と実験ではまだ答えが得られていないので、何らかの助けを期待しています.

以前のバージョンでは追加したい列がなかったアプリケーションのインストール ファイルを変更しています。列を手動で追加したくはありませんが、インストール ファイルに、新しい列がテーブルにまだ存在しない場合にのみ追加します。

テーブルは次のように作成されます。

CREATE TABLE IF NOT EXISTS `#__comm_subscribers` (
      `subscriber_id` int(11) NOT NULL auto_increment,
      `user_id` int(11) NOT NULL default '0',
      `subscriber_name` varchar(64) NOT NULL default '',
      `subscriber_surname` varchar(64) NOT NULL default '',
      `subscriber_email` varchar(64) NOT NULL default '',
      `confirmed` tinyint(1) NOT NULL default '0',
      `subscribe_date` datetime NOT NULL default '0000-00-00 00:00:00',
      PRIMARY KEY  (`subscriber_id`),
      UNIQUE KEY `subscriber_email` (`subscriber_email`)
    ) ENGINE=MyISAM CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' COMMENT='Subscribers for Comm are stored here.';

以下を create table ステートメントの下に追加すると、列が既に存在する (そしておそらくデータが取り込まれている) 場合に何が起こるかわかりません。

ALTER TABLE `#__comm_subscribers` ADD `subscriber_surname`;
ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';

そこで、どこかで見つけた以下を試してみました。これは機能していないようですが、適切に使用したかどうかは完全にはわかりません。

/*delimiter '//'
CREATE PROCEDURE addcol() BEGIN
IF NOT EXISTS(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME='subscriber_surname' AND TABLE_NAME='#__comm_subscribers'
)
THEN
    ALTER TABLE `#__comm_subscribers`
    ADD COLUMN `subscriber_surname` varchar(64) NOT NULL default '';
END IF;
END;
//
delimiter ';'
CALL addcol();
DROP PROCEDURE addcol;*/

誰かがこれを行う良い方法を持っていますか?

4

16 に答える 16

86

これが実際の解決策です (Solaris で MySQL 5.0 を試したところです):

DELIMITER $$

DROP PROCEDURE IF EXISTS upgrade_database_1_0_to_2_0 $$
CREATE PROCEDURE upgrade_database_1_0_to_2_0()
BEGIN

-- rename a table safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND TABLE_NAME='my_old_table_name') ) THEN
    RENAME TABLE 
        my_old_table_name TO my_new_table_name,
END IF;

-- add a column safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND COLUMN_NAME='my_additional_column' AND TABLE_NAME='my_table_name') ) THEN
    ALTER TABLE my_table_name ADD my_additional_column varchar(2048) NOT NULL DEFAULT '';
END IF;

END $$

CALL upgrade_database_1_0_to_2_0() $$

DELIMITER ;

一見、必要以上に複雑に見えるかもしれませんが、ここでは次の問題に対処する必要があります。

  • IFステートメントはストアド プロシージャでのみ機能し、mysql クライアントなどで直接実行した場合は機能しません。
  • より洗練された簡潔なSHOW COLUMNSものはストアド プロシージャでは機能しないため、INFORMATION_SCHEMA を使用する必要があります
  • MySQL では区切りステートメントの構文が変なので、ストアド プロシージャを作成できるように区切り文字を再定義する必要があります。区切り文字を元に戻すことを忘れないでください!
  • INFORMATION_SCHEMA はすべてのデータベースに対してグローバルです。 でフィルタリングすることを忘れないでくださいTABLE_SCHEMA=DATABASE()DATABASE()現在選択されているデータベースの名前を返します。
于 2010-08-11T13:01:48.497 に答える
56

MariaDB を使用している場合は、ストアド プロシージャを使用する必要はありません。たとえば、次のように使用します。

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name tinyint(1) DEFAULT 0;

こちらをご覧ください

于 2015-11-17T11:01:17.103 に答える
50

INFORMATION_SCHEMA5.0より前のMySQLではサポートされていないことに注意してください。また、5.0より前のストアドプロシージャはサポートされていないため、MySQL 4.1をサポートする必要がある場合、このソリューションは適切ではありません。

データベースの移行を使用するフレームワークで使用されるソリューションの1つは、スキーマのリビジョン番号をデータベースに記録することです。単一の列と単一の行を持ち、現在有効なリビジョンを示す整数を持つ単なるテーブル。スキーマを更新するときは、番号を増やしてください。

別の解決策は、コマンドを試すことです。ALTER TABLE ADD COLUMN列がすでに存在する場合は、エラーがスローされます。

ERROR 1060 (42S21): Duplicate column name 'newcolumnname'

エラーをキャッチし、アップグレードスクリプトで無視します。

于 2009-06-09T23:43:17.190 に答える
36

回答のほとんどは、ストアド プロシージャに列を安全に追加する方法を扱っています。ストアド プロシージャを使用せずにテーブルに列を安全に追加する必要があり、MySQL ではSPIF Exists()外での使用が許可されていないことがわかりました。同じ状況の誰かを助けるかもしれないという私の解決策を投稿します。

SELECT count(*)
INTO @exist
FROM information_schema.columns 
WHERE table_schema = database()
and COLUMN_NAME = 'original_data'
AND table_name = 'mytable';

set @query = IF(@exist <= 0, 'alter table intent add column mycolumn4 varchar(2048) NULL after mycolumn3', 
'select \'Column Exists\' status');

prepare stmt from @query;

EXECUTE stmt;
于 2012-11-14T23:22:44.550 に答える
24

これを行う別の方法は、次のエラーを無視することdeclare continue handlerです。

delimiter ;;
create procedure foo ()
begin
    declare continue handler for 1060 begin end;
    alter table atable add subscriber_surname varchar(64);
end;;
call foo();;

existsサブクエリよりもこの方法の方がきれいだと思います。特に、追加する列が多く、スクリプトを数回実行したい場合。

継続ハンドラーの詳細については、http://dev.mysql.com/doc/refman/5.0/en/declare-handler.htmlを参照してください。

于 2011-06-25T05:38:16.010 に答える
7

MySQL 5.5.19 を使用しています。

エラーなしで実行および再実行できるスクリプトを用意するのが好きです。特に、エラーや警告のないスクリプトを実行しているときに警告が残っているように見える場合は、後で再び表示されます。フィールドの追加に関する限り、入力を少し減らす手順を自分で書きました。

-- add fields to template table to support ignoring extra data 
-- at the top/bottom of every page
CALL addFieldIfNotExists ('template', 'firstPageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageFooterBeginY', 'INT NOT NULL DEFAULT 792');

addFieldIfNotExistsプロシージャを作成するコードは次のとおりです。

DELIMITER $$

DROP PROCEDURE IF EXISTS addFieldIfNotExists 
$$

DROP FUNCTION IF EXISTS isFieldExisting 
$$

CREATE FUNCTION isFieldExisting (table_name_IN VARCHAR(100), field_name_IN VARCHAR(100)) 
RETURNS INT
RETURN (
    SELECT COUNT(COLUMN_NAME) 
    FROM INFORMATION_SCHEMA.columns 
    WHERE TABLE_SCHEMA = DATABASE() 
    AND TABLE_NAME = table_name_IN 
    AND COLUMN_NAME = field_name_IN
)
$$

CREATE PROCEDURE addFieldIfNotExists (
    IN table_name_IN VARCHAR(100)
    , IN field_name_IN VARCHAR(100)
    , IN field_definition_IN VARCHAR(100)
)
BEGIN

    -- http://javajon.blogspot.com/2012/10/mysql-alter-table-add-column-if-not.html

    SET @isFieldThere = isFieldExisting(table_name_IN, field_name_IN);
    IF (@isFieldThere = 0) THEN

        SET @ddl = CONCAT('ALTER TABLE ', table_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', 'ADD COLUMN') ;
        SET @ddl = CONCAT(@ddl, ' ', field_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', field_definition_IN);

        PREPARE stmt FROM @ddl;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;

    END IF;

END;
$$

列を安全に変更する手順は書きませんでしたが、上記の手順は簡単に変更できると思います。

于 2012-10-21T21:03:40.700 に答える
5

OP の sproc を取得し、再利用可能でスキーマに依存しないようにしました。明らかに、それでも MySQL 5 が必要です。

DROP PROCEDURE IF EXISTS AddCol;

DELIMITER //

CREATE PROCEDURE AddCol(
    IN param_schema VARCHAR(100),
    IN param_table_name VARCHAR(100),
    IN param_column VARCHAR(100),
    IN param_column_details VARCHAR(100)
) 
BEGIN
    IF NOT EXISTS(
    SELECT NULL FROM information_schema.COLUMNS
    WHERE COLUMN_NAME=param_column AND TABLE_NAME=param_table_name AND table_schema = param_schema
    )
    THEN
        set @paramTable = param_table_name ;
        set @ParamColumn = param_column ;
        set @ParamSchema = param_schema;
        set @ParamColumnDetails = param_column_details;
        /* Create the full statement to execute */
        set @StatementToExecute = concat('ALTER TABLE `',@ParamSchema,'`.`',@paramTable,'` ADD COLUMN `',@ParamColumn,'` ',@ParamColumnDetails);
        /* Prepare and execute the statement that was built */
        prepare DynamicStatement from @StatementToExecute ;
        execute DynamicStatement ;
        /* Cleanup the prepared statement */
        deallocate prepare DynamicStatement ;

    END IF;
END //

DELIMITER ;
于 2013-03-29T18:19:51.060 に答える
1

PDO に列が存在するかどうかを確認する (100%)

{
    if(isset($_POST['Add']))
    {
        $ColumnExist = $dbh->prepare("SELECT * FROM ColumnChecker where column_name='$insert_column_name' LIMIT 1");
        $ColumnExist ->execute();
        $ColumnName = $ColumnExist->fetch(2);
        $Display_Column_Name = $ColumnName['column_name'];

        if($Display_Column_Name == $insert_column_name)
        {
            echo "$Display_Column_Name already exist";
        } //*****************************
        else 
        {
            $InsertColumn = $dbh->prepare("insert into ColumnChecker ( column_name ) values ('$insert_column_name')");
            $InsertColumn->execute();

            if($InsertColumn)
            {
                $Add = $dbh->prepare("ALTER TABLE `$Table` ADD `$insert_column_name` $insert_column_type($insert_column_Length) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ");
                $Add->execute();

                if($Add)
                {
                    echo 'Table has been updated';  
                }
                else 
                {
                    echo 'Sorry! Try again...'; 
                }
            }   
        }
    }
}#Add Column into Table :)
于 2012-08-16T08:28:00.560 に答える
1

Jake https://stackoverflow.com/a/6476091/6751901の手順は、新しい列を追加するための非常にシンプルで優れたソリューションですが、1 行追加されています。

DROP PROCEDURE IF EXISTS foo;;

後でそこに新しい列を追加できます。次回も機能します。

delimiter ;;
DROP PROCEDURE IF EXISTS foo;;
create procedure foo ()
begin
    declare continue handler for 1060 begin end;
    alter table atable add subscriber_surname varchar(64);
    alter table atable add subscriber_address varchar(254);
end;;
call foo();;
于 2016-08-24T10:00:10.227 に答える
1

ストアドプロシージャスクリプトを試してみました。問題は'区切り文字の周りのマークにあるようです。MySQL Docsは、区切り文字に一重引用符が必要ないことを示しています。

あなたが望んでいるのは:

delimiter //

それ以外の:

delimiter '//'

私のために働く:)

于 2010-07-08T20:38:32.533 に答える
1

PHP > PDO で列を追加する最良の方法:

$Add = $dbh->prepare("ALTER TABLE `YourCurrentTable` ADD `YourNewColumnName` INT NOT NULL");
$Add->execute();

注: 表の列は反復可能ではありません。つまり、列の存在を確認する必要はありませんが、問題を解決するために上記のコードを確認します。

たとえば、アラートが機能する場合は 1、0 でない場合は、列が存在することを意味します。:)

于 2012-08-15T21:59:15.163 に答える
0
$smpt = $pdo->prepare("SHOW fields FROM __TABLE__NAME__");
$smpt->execute();
$res = $smpt->fetchAll(PDO::FETCH_ASSOC);
//print_r($res);

次に、$res by cycle で、次のように列 Smth のキーを探します。

    if($field['Field'] == '_my_col_'){
       return true;
    }
+

**Below code is good for checking column existing in the WordPress tables:**
public static function is_table_col_exists($table, $col)
    {
        global $wpdb;
        $fields = $wpdb->get_results("SHOW fields FROM {$table}", ARRAY_A);
        foreach ($fields as $field)
        {
            if ($field['Field'] == $col)
            {
                return TRUE;
            }
        }

        return FALSE;
    }
于 2015-09-06T18:19:45.707 に答える