我试图用选择声明,以让所有的列从某些MySQL表只有一个除外。是有一个简单的方式做到这一点?

编辑:有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

没有得到column3,虽然也许你是寻找一个更一般的解决方案吗?

如果你是想要排除的价值的一个领域,例如出于安全关切、敏感信息,你可以检索,列为空。

例如

SELECT *, NULL AS salary FROM users

据我所知,没有。你可以做一些事情,如:

SELECT col1, col2, col3, col4 FROM tbl

并手动选择列您想要的。但是,如果你想了很多的列,然后你可能只是想要做的:

SELECT * FROM tbl 

只是忽略什么你不想要的。

在特定情况下,我要建议:

SELECT * FROM tbl

除非你只想要一些专栏。如果你只想四列,则:

SELECT col3, col6, col45, col 52 FROM tbl

将被罚款,但如果你想50列,那么任何代码,这使得查询将成为(?) 难于阅读。

同时试图解决方案通过@Mahomedalid和@朱奈德,我发现了一个问题。所以想过分享它。如果列名是具有空间或连字符的像检查,在随后的查询将失败。简单的解决方法是使用反引号围栏的名称。修改后的查询下

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;

如果柱,你不想选择了大量的数据,并且你不想把它包括由于速度的问题和选择的其他列通常,我建议创建一个新的表格有一场,你通常不会选择与一个关键的原始表,并删除该段的原始表格。加入该表格当的额外领域实际上是必需的。

你可以用 描述,忽略大小 和使用的结果,以产生选择声明的动态。

我的主要问题是许多列我当加入表格。虽然这不是回答你的问题,(如何选择所有,但某些列从 一个 表),我认为这是值得一提的是,你可以指定 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') )

结果是所有列从用户表,以及两个附加列它们加入的元表。

我喜欢这个答案 @Mahomedalid 除了这一事实告知评论 @Bill Karwin.可能提出的问题 @Jan Koritak 是真的,我所面临的,但是我必须找到一个把戏,只是想分享它在这里任何人都面临的问题。

我们可以替代该替换的功能与其条款,在子查询的准备的发言是这样的:

使用我的表和列的名字

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列,col3,col4,...col53

我同意,它不足以 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","whatevercolumn")

因此,在选择你可以用这样的:

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

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

同意@Mahomedalid的答复。但我不想这样做准备的发言,我不想类型的所有领域。所以我是一个愚蠢的解决方案。去表,在头文件->sql->选择,它转储查询复制取代和做!:)

虽然我同意托马斯答复(+1;)),我想添加的告诫,我就假定列于你 不不 想包含几乎没有任何数据。如果它包含了大量的文本,xml或二进制的,则需要时间选择每个柱。你的表现将受到其他方式。干杯!

是的,虽然它可以高I/O取决于发表这是一个解决办法,我发现它。

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

答案发布的通过Mahomedalid有一个小问题:

内部替换功能来代替"<columns_to_delete>,"通过"的",这替换了一个问题,如果领域以取代是最后一个在concat串由于最后一个没有char逗号","并不是从中删除。

我提议:

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> 和`

列删除,替换为string"FIELD_REMOVED"在我的情况这一工作,因为我想到安全存储器中。(该领域我是删除一BLOB约1MB)

根据@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;

如果你有很多cols,使用这sql改变group_concat_max_len

SET @@group_concat_max_len = 2048;

可我有个解决 Jan Koritak的 指出的差异

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'

如果它是始终是同一个柱,然后您可以创建一个看法,即不拥有它。

否则,不,我不这么认为。

你可以使用SQL产生SQL如果你喜欢和评估SQL它产生。这是一个普遍解决方案,因为它提取的列名从信息架构。这里是一个例从Unix command line.

  • MYSQL与mysql命令
  • 表表的名字
  • 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

你真的会只需要提取该列名称以这种方式只有一次建造列清单排列,然后只是使用的查询已经建成。

所以是这样的:

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 字符串中的查询结构。

我想添加另一种观点认为为了解决这个问题,特别是如果你有一个小的列数删除。

你可以使用数据库等工具 MySQL工作台 为了产生选择的发言为你,所以你只需要手动删除那些列为所产生的发言,并复制到你SQL脚本。

在MySQL工作台的方式产生:

右击表>发送到Sql编>选择的所有声明。

所接受的答案有几个缺点。

  • 它失败,其中表或列名要求反引号
  • 它失败如果你想忽略是在列表的最后
  • 它需要列表的名字的两倍(一次的选择,另一个用于查询文本),这是多余和不必要的
  • 它可能返回的名字在列 错误了

所有这些问题是可以克服的,简单地包括在反引号 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';

我深throing出一个答案为这个,把这是我一直做这坦率地说,它的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]);

选择*SQL反模式.它不应该在生产中使用的代码,用于多种原因,包括:

这需要小点的时间来处理。当事情都运行数以百万计的时候,那些微小的位的问题。一个缓慢的数据库里的缓慢,是造成这种类型的草率的编码,整个是最难的一种表现。

这意味着你可能派遣更多的数据比你需要这将导致两个服务器和网络的瓶颈。如果你有一个内部联接的机会派更多的数据比你需要的是100%以上。

它会导致维护问题,特别是当你已经加入新列不想看到无处不在。另外,如果你有一个新的栏,可能需要做些什么来的界面,以确定该怎么做,列。

它可以打破的风景(我知道这是真的,在SQl服务器,它可能会或可能不是真的在mysql).

如果有人愚蠢的足够的重建表列在不同了(你不应该做的,但它发生的所有德时间),有各种各样的代码可以打破。并重码插入例如在那里突然间你都把城市入address_3领域,因为没有指定,该数据库只能去的顺序列。这是够糟糕的时的数据类型的变化,但更糟的是当交换列有相同的数据类型,因为你可以去的某个时候插入糟糕的数据就是一个烂摊子收拾。你需要关心的数据的完整性。

如果使用一个插入,它将打破插入如果一个新的栏中加入一个表,但不是其他。

它可能会破坏触发器。触发的问题可能很难诊断。

添加了所有这种反对的时间需要增加在列名(见鬼你甚至可能有一个界面,允许你拖过列名(我知道我在SQL服务器上,我敢打赌有一些办法来做到这一点是一些工具用于编写mysql查询。) 让我们来看看,"我可能会导致维修问题,我可能会导致性能的问题和我可能会导致数据完整性问题,但是嘿我救了五分钟的开发时间。" 真的只是放在具体列您想要的。

我也建议你读这本书: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