質問

select ステートメントを使用して、特定の MySQL テーブルから 1 つを除くすべての列を取得しようとしています。これを行う簡単な方法はありますか?

編集:このテーブルには 53 列あります (私のデザインではありません)

役に立ちましたか?

解決

実際には方法があります。これを行うにはもちろん権限が必要です...

SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME), '<columns_to_omit>,', '') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table>' AND TABLE_SCHEMA = '<database>'), ' FROM <table>');

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

交換中 <table>, <database> and <columns_to_omit>

他のヒント

mysql 定義 (マニュアル) にはそのようなものはありません。しかし、列の数が非常に多い場合は、 col1, ..., col100, 、次のものが役立ちます。

mysql> CREATE TEMPORARY TABLE temp_tb SELECT * FROM orig_tb;
mysql> ALTER TABLE temp_tb DROP col_x;
mysql> SELECT * FROM temp_tb;

この場合、ビューの方がうまく機能するでしょうか?

CREATE VIEW vwTable
as  
SELECT  
    col1  
    , col2  
    , col3  
    , col..  
    , col53  
FROM table

できるよ:

SELECT column1, column2, column4 FROM table WHERE whatever

列 3 を取得することはできませんでしたが、おそらくより一般的な解決策を探していたのではないでしょうか?

フィールドの値を除外したい場合、例:セキュリティ上の懸念や機密情報の場合は、その列を null として取得できます。

例えば

SELECT *, NULL AS salary FROM users

私の知る限り、それはありません。次のようなことができます。

SELECT col1, col2, col3, col4 FROM tbl

必要な列を手動で選択します。ただし、多数の列が必要な場合は、次のことを実行するとよいでしょう。

SELECT * FROM tbl 

そして、望まないものは無視してください。

あなたの特定のケースでは、次のことをお勧めします。

SELECT * FROM tbl

数列だけが必要な場合を除きます。4 つの列だけが必要な場合は、次のようにします。

SELECT col3, col6, col45, col 52 FROM tbl

これは問題ありませんが、50 列が必要な場合、クエリを作成するコードは (あまりにも?) 読みにくくなります。

@Mahomedalid と @Junaid による解決策を試しているときに、問題が見つかりました。そこでそれを共有することを考えました。チェックインのように列名にスペースやハイフンが含まれている場合、クエリは失敗します。簡単な回避策は、列名の前後にバックティックを使用することです。変更されたクエリは以下のとおりです

SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(CONCAT("`", COLUMN_NAME, "`")) FROM
INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;

選択したくない列に大量のデータが含まれており、速度の問題からその列を含めたくなく、他の列を頻繁に選択する場合は、新しいテーブルを作成することをお勧めします。元のテーブルへのキーを使用して通常は選択しない 1 つのフィールドを使用して、元のテーブルからフィールドを削除します。追加のフィールドが実際に必要な場合は、テーブルを結合します。

使用できます my_table の説明 そしてその結果を使用して SELECT ステートメントを動的に生成します。

私の主な問題は、テーブルを結合するときに多くの列が発生することです。これはあなたの質問に対する答えではありませんが(特定の列を除くすべての列を選択する方法) 1つ 表)、指定できることは言及する価値があると思います table. 単に指定するのではなく、特定のテーブルからすべての列を取得するには .

これがどのように非常に役立つかを示す例を次に示します。

select users.*, phone.meta_value as phone, zipcode.meta_value as zipcode

from users

left join user_meta as phone
on ( (users.user_id = phone.user_id) AND (phone.meta_key = 'phone') )

left join user_meta as zipcode
on ( (users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode') )

結果は、users テーブルのすべての列と、メタ テーブルから結合された 2 つの追加の列です。

からの答えが気に入りました @Mahomedalid この事実に加えて、からのコメントで通知されました @Bill Karwin. 。によって引き起こされる可能性のある問題 @Jan Koritak それは本当ですが、私はその問題に直面したことがありますが、そのためのトリックを見つけたので、問題に直面している人のためにここで共有したいと思います。

次のように、準備されたステートメントのサブクエリ内の REPLACE 関数を where 句に置き換えることができます。

テーブル名と列名を使用する

SET @SQL = CONCAT('SELECT ', (SELECT GROUP_CONCAT(COLUMN_NAME) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'users' AND COLUMN_NAME NOT IN ('id')), ' FROM users');
PREPARE stmt1 FROM @SQL;
EXECUTE stmt1;

したがって、これはフィールドのみを除外します id だがしかし company_id

これが解決策を探している人に役立つことを願っています。

よろしく

すべての列をクエリする場合でも、クエリを実行する列を指定することをお勧めします。

したがって、ステートメント内の各列の名前を書くことをお勧めします(不要な列を除く)。

SELECT
    col1
    , col2
    , col3
    , col..
    , col53

FROM table

ただやってください

SELECT * FROM table WHERE whatever

次に、好みのプログラミング言語で列をドロップします。php

while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
   unset($data["id"]);
   foreach ($data as $k => $v) { 
      echo"$v,";
   }      
}

私はすべての列をリストするという「単純な」解決策に同意しますが、これは面倒な作業であり、タイプミスにより多くの時間が無駄になる可能性があります。「getTableColumns」関数を使用して、クエリへの貼り付けに適した列の名前を取得します。あとは、不要なものを削除するだけです。

CREATE FUNCTION `getTableColumns`(tablename varchar(100)) 
          RETURNS varchar(5000) CHARSET latin1
BEGIN
  DECLARE done INT DEFAULT 0;
  DECLARE res  VARCHAR(5000) DEFAULT "";

  DECLARE col  VARCHAR(200);
  DECLARE cur1 CURSOR FOR 
    select COLUMN_NAME from information_schema.columns 
    where TABLE_NAME=@table AND TABLE_SCHEMA="yourdatabase" ORDER BY ORDINAL_POSITION;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
  OPEN cur1;
  REPEAT
       FETCH cur1 INTO col;
       IF NOT done THEN 
          set res = CONCAT(res,IF(LENGTH(res)>0,",",""),col);
       END IF;
    UNTIL done END REPEAT;
  CLOSE cur1;
  RETURN res;

結果はカンマ区切りの文字列を返します。例:

列1、列2、列3、列4、...列53

それだけでは十分ではないことに同意します Select *, 他の場所で述べたように、必要のないものが BLOB である場合、そのオーバーヘッドが発生することは望ましくありません。

私なら作成します ビュー 必要なデータがあれば、次のことができます Select * 快適 -- データベース ソフトウェアがサポートしている場合。それ以外の場合は、巨大なデータを別のテーブルに置きます。

最初は正規表現を使用できると思いましたが、読んでいると MYSQL ドキュメント できないようです。私だったら、別の言語 (PHP など) を使用して取得する列のリストを生成し、それを文字列として保存し、それを使用して SQL を生成するでしょう。

私もこれが欲しかったので、代わりに関数を作成しました。

public function getColsExcept($table,$remove){
    $res =mysql_query("SHOW COLUMNS FROM $table");

    while($arr = mysql_fetch_assoc($res)){
        $cols[] = $arr['Field'];
    }
    if(is_array($remove)){
        $newCols = array_diff($cols,$remove);
        return "`".implode("`,`",$newCols)."`";
    }else{
        $length = count($cols);
        for($i=0;$i<$length;$i++){
            if($cols[$i] == $remove)
                unset($cols[$i]);
        }
        return "`".implode("`,`",$cols)."`";
    }
}

どのように機能するかというと、テーブルに入力してから、不要な列を入力するか、配列として入力します。array("id","name","任意の列")

したがって、select では次のように使用できます。

mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");

または

mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");

@Mahomedalidの答えに同意します。しかし、準備されたステートメントのようなことはしたくなかったし、すべてのフィールドを入力したくありませんでした。それで、私が持っていたのは愚かな解決策でした。phpmyadmin->sql->select でテーブルに移動すると、クエリのコピーがダンプされ、置換されて完了です。:)

Thomas の答え (+1 ;)) には同意しますが、次のようなコラムを想定するという注意点を追加したいと思います。 しないでください want にはデータがほとんど含まれていません。膨大な量のテキスト、XML、またはバイナリ BLOB が含まれている場合は、時間をかけて各列を個別に選択してください。そうしないとパフォーマンスが低下します。乾杯!

はい、テーブルによっては I/O が高くなる可能性がありますが、ここでは私が見つけた回避策を示します。

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

Mahomedalid が投稿した回答には小さな問題があります。

内部の置換関数コードが置換されていました。<columns_to_delete>," by "" では、置換するフィールドが連結文字列の最後のフィールドである場合、最後のフィールドには文字カンマ "," がなく、文字列から削除されないため、この置換には問題があります。

わたしの提案:

SET @sql = CONCAT('SELECT ', (SELECT REPLACE(GROUP_CONCAT(COLUMN_NAME),
                  '<columns_to_delete>', '\'FIELD_REMOVED\'')
           FROM INFORMATION_SCHEMA.COLUMNS
           WHERE TABLE_NAME = '<table>'
             AND TABLE_SCHEMA = '<database>'), ' FROM <table>');

交換中 <table>, <database> そして「」

私の場合、削除された列は文字列「FIELD_REMOVED」に置き換えられます。これは、メモリを安全にしようとしていたためです。(削除していたフィールドは約 1MB の BLOB です)

@Mahomedalidの回答に基づいて、「mysqlの一部を除くすべての列を選択」をサポートするためにいくつかの改善を行いました。

SET @database    = 'database_name';
SET @tablename   = 'table_name';
SET @cols2delete = 'col1,col2,col3';

SET @sql = CONCAT(
'SELECT ', 
(
    SELECT GROUP_CONCAT( IF(FIND_IN_SET(COLUMN_NAME, @cols2delete), NULL, COLUMN_NAME ) )
    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @tablename AND TABLE_SCHEMA = @database
), 
' FROM ',
@tablename);

SELECT @sql;

列がたくさんある場合は、この SQL を使用して group_concat_max_len を変更します。

SET @@group_concat_max_len = 2048;

解決策があるかも知れません ヤン・コリタックさんの 矛盾を指摘した

SELECT CONCAT('SELECT ',
( SELECT GROUP_CONCAT(t.col)
FROM
(
    SELECT CASE
    WHEN COLUMN_NAME = 'eid' THEN NULL
    ELSE COLUMN_NAME
    END AS col 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'
) t
WHERE t.col IS NOT NULL) ,
' FROM employee' );

テーブル :

SELECT table_name,column_name 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'employee' AND TABLE_SCHEMA = 'test'

================================

table_name  column_name
employee    eid
employee    name_eid
employee    sal

================================

クエリ結果:

'SELECT name_eid,sal FROM employee'

常に同じ 1 列である場合は、その列を含まないビューを作成できます。

そうでなければ、私はそうは思いません。

必要に応じて、SQL を使用して SQL を生成し、生成される SQL を評価することができます。これは、情報スキーマから列名を抽出するための一般的な解決策です。Unix コマンドラインの例を次に示します。

置き換える

  • MYSQL と mysql コマンド
  • TABLE とテーブル名
  • EXCLUDEDFIELD (除外されたフィールド名)
echo $(echo 'select concat("select ", group_concat(column_name) , " from TABLE") from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1) | MYSQL

実際には、この方法で列名を抽出する必要があるのは 1 回だけで、その列を除外した列リストを作成し、作成したクエリを使用するだけです。

したがって、次のようなものです:

column_list=$(echo 'select group_concat(column_name) from information_schema.columns where table_name="TABLE" and column_name != "EXCLUDEDFIELD" group by "t"' | MYSQL | tail -n 1)

これで、再利用できるようになります $column_list 構築するクエリ内の文字列。

特に削除する列の数が少ない場合に、この問題を解決するために別の観点を追加したいと思います。

次のような DB ツールを使用できます MySQL ワークベンチ select ステートメントを生成するには、生成されたステートメントのこれらの列を手動で削除し、それを SQL スクリプトにコピーするだけです。

MySQL Workbench では、これを生成する方法は次のとおりです。

テーブルを右クリック -> SQL エディターに送信 -> すべてのステートメントを選択。

受け入れられた回答にはいくつかの欠点があります。

  • テーブル名または列名にバッククォートが必要な場合は失敗します。
  • 省略したい列がリストの最後にある場合は失敗します。
  • テーブル名を 2 回リストする必要があります (1 回は選択用、もう 1 回はクエリ テキスト用)。これは冗長で不要です。
  • 潜在的に列名を返す可能性があります。 注文間違い

これらの問題はすべて、単にバッククォートを含めることで解決できます。 SEPARATOR あなたのための GROUP_CONCAT そして、を使用して WHERE 代わりに条件を付ける REPLACE(). 。私の目的 (そして他の多くの目的も想像します) として、テーブル自体に表示されるのと同じ順序で列名を返す必要がありました。これを達成するために、ここでは明示的なメソッドを使用します。 ORDER BY 内の節 GROUP_CONCAT() 関数:

SELECT CONCAT(
    'SELECT `',
    GROUP_CONCAT(COLUMN_NAME ORDER BY `ORDINAL_POSITION` SEPARATOR '`,`'),
    '` FROM `',
    `TABLE_SCHEMA`,
    '`.`',
    TABLE_NAME,
    '`;'
)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE `TABLE_SCHEMA` = 'my_database'
    AND `TABLE_NAME` = 'my_table'
    AND `COLUMN_NAME` != 'column_to_omit';

これに対する答えを出すのがかなり遅れています。これが私がいつもやってきた方法です。率直に言って、ベストアンサーよりも 100 倍優れており、きちんとしています。誰かが見てくれることを願うだけです。そしてそれが役に立つと思う

    //create an array, we will call it here. 
    $here = array();
    //create an SQL query in order to get all of the column names
    $SQL = "SHOW COLUMNS FROM Table";
        //put all of the column names in the array
        foreach($conn->query($SQL) as $row) {
            $here[] = $row[0];
        }
    //now search through the array containing the column names for the name of the column, in this case i used the common ID field as an example
    $key = array_search('ID', $here);
    //now delete the entry
    unset($here[$key]);

Select * は SQL アンチパターンです。次のようなさまざまな理由から、実稼働コードでは使用しないでください。

処理には少し時間がかかります。何百万回も実行されると、それらの小さな部分が重要になることがあります。このようなずさんなコーディングが原因で速度が低下するデータベースは、パフォーマンスの調整が最も困難です。

これは、必要以上のデータを送信している可能性があり、サーバーとネットワークの両方のボトルネックを引き起こしていることを意味します。内部結合がある場合、必要以上のデータが送信される可能性は 100% です。

特に、どこにでも表示されたくない新しい列を追加した場合、メンテナンスの問題が発生します。さらに、新しい列がある場合は、その列をどう扱うかを決定するためにインターフェイスに対して何らかの操作を行う必要がある場合があります。

ビューが壊れる可能性があります (これが SQL サーバーでは真実であることはわかっていますが、mysql では真実である場合とそうでない場合があります)。

誰かが別の順序で列を含むテーブルを再構築するほど愚かな場合 (これはすべきではありませんが、それは常に起こります)、あらゆる種類のコードが壊れる可能性があります。特に、指定しないとデータベースは列の順序でしか処理できないため、たとえば突然 address_3 フィールドに都市を入力するような挿入のコードを作成します。これは、データ型が変更される場合には十分に問題ですが、スワップされた列のデータ型が同じ場合は、クリーンアップが面倒な不正なデータが挿入される可能性があるため、さらに悪いことになります。データの整合性を考慮する必要があります。

これを挿入で使用すると、一方のテーブルに新しい列が追加され、もう一方のテーブルには追加されなかった場合、挿入が中断されます。

トリガーが壊れる可能性があります。トリガーの問題は診断が難しい場合があります。

これらすべてを、列名を追加するのにかかる時間と合計してください (列名をドラッグできるインターフェイスさえあるかもしれません (SQL Server ではそうしていると思いますが、何らかの方法があると思います)これは、mysql クエリを作成するために使用するツールです。) 見てみましょう、「メンテナンスの問題、パフォーマンスの問題、データの整合性の問題が発生する可能性がありますが、開発時間を 5 分節約できました。」必要な特定の列に入力します。

この本も読むことをお勧めします。http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers-ebook/dp/B00A376BB2/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1389896688&sr=1-1&keywords=sql+antipatterns

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top