选择MySQL以外的所有列?

时间:2008-08-12 18:45:55

标签: mysql select

我正在尝试使用select语句来获取某个MySQL表中的所有列,除了一个。有一种简单的方法可以做到这一点吗?

编辑:此表中有53列(不是我的设计)

32 个答案:

答案 0 :(得分:203)

实际上有一种方法,你当然需要拥有这样做的权限......

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>

答案 1 :(得分:46)

在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;

答案 2 :(得分:42)

在这种情况下,View会更好用吗?

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

答案 3 :(得分:33)

你可以这样做:

SELECT column1, column2, column4 FROM table WHERE whatever

没有获得第3列,但也许您正在寻找更通用的解决方案?

答案 4 :(得分:31)

如果您要排除某个字段的值,例如对于安全问题/敏感信息,您可以将该列检索为空。

e.g。

SELECT *, NULL AS salary FROM users

答案 5 :(得分:22)

据我所知,没有。你可以这样做:

SELECT col1, col2, col3, col4 FROM tbl

并手动选择所需的列。但是,如果你想要很多列,那么你可能只想做一个:

SELECT * FROM tbl 

然后忽略你不想要的东西。

在您的特定情况下,我建议:

SELECT * FROM tbl

除非您只想要几列。如果您只想要四列,那么:

SELECT col3, col6, col45, col 52 FROM tbl

没关系,但是如果你想要50列,那么任何使查询的代码都会变得(太?)难以阅读。

答案 6 :(得分:13)

在尝试@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;

答案 7 :(得分:10)

如果您不想选择的列中包含大量数据,并且由于速度问题而您不想包含它,并且您经常选择其他列,我建议您创建带有一个字段的新表,通常不会使用原始表的键选择该字段,并从原始表中删除该字段。在实际需要额外字段时加入表格。

答案 8 :(得分:9)

您可以使用DESCRIBE my_table并使用其结果动态生成SELECT语句。

答案 9 :(得分:7)

我的主要问题是我在连接表时获得了很多列。虽然这不是您的问题的答案(如何从一个表中选择除某些列以外的所有列),但我认为值得一提的是您可以指定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表中的所有列,以及从元表连接的另外两列。

答案 10 :(得分:5)

我喜欢@Mahomedalid的回答,除了@Bill Karwin的评论中提供的这一事实。 @Jan Koritak提出的可能问题是真的,我遇到了这个问题,但我找到了一个技巧,只是想在这里分享面对这个问题的任何人。

我们可以用Prepared语句的子查询中的where子句替换REPLACE函数,如下所示:

使用我的表名和列名

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

希望这能帮助任何寻求解决方案的人。

此致

答案 11 :(得分:4)

只做

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,";
   }      
}

答案 12 :(得分:4)

我同意列出所有列的“简单”解决方案,但这可能很麻烦,而且拼写错误可能会造成大量浪费时间。我使用函数“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;

您的结果返回逗号分隔的字符串,例如......

  

COL1,COL2,COL3,COL4,... col53

答案 13 :(得分:4)

即使您查询所有列,最好指定要查询的列。

所以我建议你在声明中写下每一列的名称(不包括你不想要的那个)。

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

FROM table

答案 14 :(得分:3)

起初我以为你可以使用正则表达式,但正如我一直在阅读MYSQL docs,你似乎不能。如果我是你,我会使用另一种语言(如PHP)来生成您想要获取的列的列表,将其存储为字符串然后使用它来生成SQL。

答案 15 :(得分:3)

我同意Select *是不够的,如果你不需要那个,就像其他地方提到的那样,是BLOB,你不希望有这种开销。

我会使用所需的数据创建视图,然后您可以{_ 1}}舒适地使用 - 如果数据库软件支持它们。否则,将大量数据放在另一个表格中。

答案 16 :(得分:3)

我也想要这样,所以我创建了一个函数。

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

答案 17 :(得分:2)

虽然我同意托马斯的答案(+1;)),但我想补充一点,我认为你想要的专栏几乎不包含任何数据。如果它包含大量文本,xml或二进制blob,则请花时间单独选择每个列。否则你的表现会受到影响。干杯!

答案 18 :(得分:2)

同意@ Mahomedalid的回答。但我不想做像预备语句这样的事情,我不想输入所有字段。 所以我所拥有的是一个愚蠢的解决方案。 转到phpmyadmin-&gt; sql-&gt;选择表,它转储查询副本替换并完成! :)

答案 19 :(得分:2)

可能我有解决 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'

答案 20 :(得分:2)

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

答案 21 :(得分:2)

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

在我的情况下,删除的列被字符串“FIELD_REMOVED”替换,因为我试图安全地记忆。 (我删除的字段是大约1MB的BLOB)

答案 22 :(得分:2)

是的,虽然它可能是高I / O,具体取决于表格,这是我找到的解决方法。

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

答案 23 :(得分:1)

如果它总是相同的一列,那么你可以创建一个没有它的视图。

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

答案 24 :(得分:1)

我想添加另一个观点以解决此问题,特别是如果您要删除少量列。

您可以使用MySQL Workbench之类的数据库工具为您生成select语句,因此您只需手动删除生成语句的列并将其复制到SQL脚本中。

在MySQL Workbench中,生成它的方法是:

右键点击表格 - &gt;发送到Sql编辑器 - &gt;选择所有声明。

答案 25 :(得分:1)

如果您愿意,可以使用SQL生成SQL并评估它生成的SQL。这是一种通用解决方案,因为它从信息模式中提取列名称。这是Unix命令行的一个例子。

  • 使用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字符串。

答案 26 :(得分:0)

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

  • 在表或列名称需要反引号的地方失败
  • 如果要忽略的列在列表的最后,则失败
  • 它需要两次列出表名(一次用于选择,另一次用于查询文本),这是多余且不必要的
  • 它可能会以错误的顺序
  • 返回列名

所有这些问题都可以通过简单地在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';

答案 27 :(得分:0)

我有一个建议,但没有解决方案。 如果您的某些列具有较大的数据集,则应尝试以下操作

SELECT *, LEFT(col1, 0) AS col1, LEFT(col2, 0) as col2 FROM table

答案 28 :(得分:0)

如果使用MySQL Workbench,则可以右键单击表,然后依次单击Send to sql editorSelect All Statement,这将创建一条列出所有字段的语句,如下所示:

SELECT `purchase_history`.`id`,
    `purchase_history`.`user_id`,
    `purchase_history`.`deleted_at`
FROM `fs_normal_run_2`.`purchase_history`;
SELECT * FROM fs_normal_run_2.purchase_history;

现在,您可以删除不需要的内容。

答案 29 :(得分:0)

尽管它可能是“非主题”,但我仍在使用此变通方法-使用mysql工作台和查询生成器-

  1. 打开列视图
  2. Shift选择您要在查询中选择的所有列(在您的情况下,除了我要执行的操作之外,所有列)
  3. 右键单击并选择发送到SQL编辑器->名称短。
  4. 现在您有了列表,然后可以将查询复制粘贴到任何地方。

enter image description here

答案 30 :(得分:-1)

我很晚才找到答案,这就是我一直这样做的方式,坦率地说,它比最好的答案好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]);

答案 31 :(得分:-4)

Select *是一个SQL反模式。它不应该在生产代码中使用,原因有很多,包括:

处理需要更长的时间。当事情运行数百万次时,那些微小的位可能很重要。一个缓慢的数据库,其中由于这种类型的草率编码引起的缓慢是最难的性能调整。

这意味着您可能发送的数据超出了您的需求,从而导致服务器和网络瓶颈。如果您有内部联接,则发送超出您需要的数据的可能性为100%。

它会导致维护问题,尤其是当您添加了不希望在任何地方看到的新列时。此外,如果您有新列,则可能需要对界面执行某些操作以确定如何处理该列。

它可以打破视图(我知道在SQl服务器中这是真的,它在mysql中可能也可能不是)。

如果有人愚蠢地用不同的顺序重建表格(你不应该这样做,但它会在一段时间内发生),各种代码都会破坏。特别是插入代码,例如突然你将城市放入address_3字段,因为没有指定,数据库只能按列的顺序排列。这在数据类型发生变化时已经足够糟糕了,但是当交换列具有相同的数据类型时更糟糕,因为您可能会在某些时候插入糟糕的数据来清理。您需要关心数据完整性。

如果在插入中使用它,如果在一个表中添加新列而不在另一个表中添加新列,则会破坏插入。

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

将所有这些添加到列名称中添加的时间(哎呀,你甚至可能有一个允许你拖动列名称的界面(我知道我在SQL Server中做,我打赌)有一些方法可以做到这一点是你用来编写mysql查询的一些工具。)让我们看看,&#34;我可能会导致维护问题,我可能会导致性能问题而且我可能会导致数据完整性问题,但是嘿我节省了五分钟的开发时间。&#34;真的只是放入你想要的特定列。

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