Выбрать все столбцы, кроме одного в MySQL?

299

Я пытаюсь использовать оператор select, чтобы получить все столбцы из определенной таблицы MySQL, кроме одного. Есть ли простой способ сделать это?

EDIT: в этой таблице 53 столбца (НЕ МОЙ ДИЗАЙН)

  • 5
    53 колонны? Я бы придерживался SELECT *, как предлагает Томас в этом случае ... разве что в этом дополнительном столбце содержится огромное количество данных, которые было бы нежелательно извлекать ...?
  • 0
    За исключением одного столбца ... Я полагаю, вы знаете, какой из них следует игнорировать, следовательно, INFORMATION_SCHEMA.columns это путь.
Показать ещё 1 комментарий
Теги:
select

28 ответов

187
Лучший ответ

На самом деле есть способ, для этого вам необходимы разрешения, чтобы сделать это...

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>

  • 18
    предостережение: запросы INFORMATION_SCHEMA имеют довольно низкую производительность, поэтому будьте осторожны, этот тип запроса ни в коем случае не является критическим путем.
  • 6
    Как сказал @Jan Koritak ниже, этот ответ на самом деле не работает, если столбцы заголовка, которые вы хотите удалить, также являются подстрокой заголовка для любых столбцов, которые вы хотите сохранить. Есть лучший ответ, похожий на этот, который можно найти здесь .
Показать ещё 7 комментариев
31

В определениях mysql (manual) такой вещи нет. Но если у вас действительно большое количество столбцов 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
    Дало мне сообщение об ошибке на 3-м шаге: «Количество столбцов не соответствует значению в строке 1». Поэтому я изменил шаг 2 на «UPDATE temp_tb SET id = NULL», и тогда это сработало.
  • 1
    Хорошо, это работает. Но когда я снова запускаю этот запрос, он выдает ошибку, что temp_tb уже существует. Сколько времени temp_tb находится в памяти? Извиняюсь, если это глупый вопрос. PS проголосовал за твой ответ.
Показать ещё 1 комментарий
30

Будет ли просмотр лучше работать в этом случае?

CREATE VIEW vwTable
as  
SELECT  
    col1  
    , col2  
    , col3  
    , col..  
    , col53  
FROM table
  • 3
    HAHA! Да, конечно. Теперь, как вы строите представление, чтобы включить все НО в один из столбцов. Я думаю, вы видите, как напрашивается оригинальный вопрос. На самом деле я нашел этот поток именно потому, что хотел создать представление, исключающее определенные столбцы, без необходимости явного перечисления всех оставшихся столбцов в определении представления.
28

Вы можете сделать:

SELECT column1, column2, column4 FROM table WHERE whatever

без получения столбца3, хотя, возможно, вы искали более общее решение?

  • 19
    +1, чтобы противодействовать понижению. Хотя это и наивный ответ, он совершенно правильный, и я считаю, что это «простой способ сделать это».
  • 0
    Согласитесь с Дэниелом Приденом, это следует принципу KISS ...
Показать ещё 6 комментариев
27

Если вы хотите исключить значение поля, например. для проблем безопасности/конфиденциальной информации вы можете получить этот столбец как null.

например.

SELECT *, NULL AS salary FROM users
  • 12
    Зачем? Не работает Если у вас есть столбец зарплата, этот запрос будет просто с результатами, имеющими два столбца с именем зарплата, один полный нулей, а другой с фактическими зарплатами.
  • 3
    @Myforwik Этот запрос действительно добавляет второй столбец salary . Но так как он получен после *, он перезаписывает оригинал. Это не красиво, но это работает.
Показать ещё 7 комментариев
23

Насколько мне известно, этого не происходит. Вы можете сделать что-то вроде:

SELECT col1, col2, col3, col4 FROM tbl

и вручную выберите нужные столбцы. Однако, если вам нужно много столбцов, вы можете просто сделать следующее:

SELECT * FROM tbl 

и просто игнорируйте то, что вы не хотите.

В вашем конкретном случае я бы предложил:

SELECT * FROM tbl

если вам не нужны только несколько столбцов. Если вам нужны только четыре столбца, то:

SELECT col3, col6, col45, col 52 FROM tbl

будет хорошо, но если вы хотите 50 столбцов, то любой код, который делает запрос, станет (слишком?) трудным для чтения.

  • 3
    Выбор * - плохой выбор всегда. Не рекомендую это. Узнайте, почему это SQl Antipattern.
12

При попытке решения @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;
  • 0
    Это ответ, который я придумал сам, после того, как принятый ответ не сработал.
11

Если столбец, который вы не хотите выбирать, имел в нем огромное количество данных, и вы не хотели его включать из-за проблем с производительностью, и вы часто выбираете другие столбцы, я бы предположил, что вы создаете новую таблицу с одним полем, которое обычно не выбирается с помощью ключа к исходной таблице и удаляет поле из исходной таблицы. Присоединяйте таблицы, когда это дополнительное поле действительно требуется.

8

Вы можете использовать DESCRIBE my_table и использовать результаты этого для генерации инструкции SELECT динамически.

6

Моя основная проблема - это много столбцов, которые я получаю при соединении таблиц. Хотя это не ответ на ваш вопрос (как выбрать все, кроме определенных столбцов из одной таблицы), я думаю, стоит упомянуть, что вы можете указать 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
    спасибо, мне нужно выбрать все столбцы первой таблицы и только одно поле из второй таблицы, и ваш ответ мне помог.
5

Мне понравился ответ от @Mahomedalid, кроме этого, сообщенного в комментарии от @Bill Karwin. Возможная проблема, поднятая @Jan Koritak, верна. Я столкнулся с этим, но я нашел для этого трюк и просто хочу поделиться ею здесь для тех, кто сталкивается с этой проблемой.

мы можем заменить функцию REPLACE предложением where в подзапросе инструкции Prepared следующим образом:

Использование имени моей таблицы и столбца

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

Надеюсь, это поможет любому, кто ищет решение.

Привет

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

4

Хорошей практикой является указать столбцы, которые вы запрашиваете, даже если вы запрашиваете все столбцы.

Поэтому я предлагаю вам написать имя каждого столбца в инструкции (исключая тот, который вы не хотите).

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

FROM table
  • 0
    почему это "хорошая практика"?
  • 0
    Он действует как контракт с кодом, и, глядя на запрос, вы точно знаете, какие данные вы можете извлечь из него, не глядя на схему таблицы.
Показать ещё 1 комментарий
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" )

Итак, в select вы можете использовать его следующим образом:

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

или

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

Сначала я думал, что вы можете использовать регулярные выражения, но, поскольку я читал MYSQL docs, похоже, вы не можете. Если бы я был вами, я бы использовал другой язык (например, PHP) для создания списка столбцов, который вы хотите получить, сохраните его как строку, а затем используйте для генерации SQL.

3

Я согласен с тем, что этого недостаточно для Select *, если тот, который вам не нужен, как упоминалось в другом месте, является BLOB, вы не хотите, чтобы эта накладная ошибка включалась.

Я бы создал представление с требуемыми данными, тогда вы можете Select * с комфортом - если программное обеспечение базы данных поддерживает их. Иначе, поместите огромные данные в другую таблицу.

2

Согласитесь с ответом @Mahomedalid. Но я не хотел делать что-то вроде подготовленного заявления, и я не хотел вводить все поля. Так что у меня было глупое решение. Перейдите в таблицу в phpmyadmin- > sql- > select, он сбрасывает копию запроса и выполняет!:)

  • 0
    Бритва Оккама. Спасибо :)
  • 0
    простой, но элегантный
2

Может быть, у меня есть решение для Ян Коритак > Указанное несоответствие

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

Если у вас есть много колоний, используйте этот sql для изменения group_concat_max_len

SET @@group_concat_max_len = 2048;
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", в моем случае это работает, потому что я пытался сохранить память. (Поле, которое я удалял, представляет собой BLOB размером около 1 МБ)

2

Да, хотя это может быть высокий ввод-вывод в зависимости от таблицы, это обходной путь, который я нашел для него.

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp
  • 0
    Это будет очень медленно для любого стола среднего размера.
2

Просто сделай

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,";
   }      
}
  • 0
    это эффективно
  • 5
    Если столбец, который вы хотите исключить, не является огромным BLOB или чем-то еще.
Показать ещё 6 комментариев
2

В то время как я согласен с ответом Томаса (+1;)), я хотел бы добавить оговорку, что я предполагаю, что колонка, которую вы не хотите, содержит едва ли какие-либо данные. Если он содержит огромное количество текста, xml или двоичных blobs, то найдите время, чтобы выбрать каждый столбец отдельно. В противном случае ваша производительность будет нарушена. Ура!

1

Я хотел бы добавить еще одну точку зрения для решения этой проблемы, особенно если у вас есть небольшое количество столбцов для удаления.

Для создания оператора select вы можете использовать инструмент DB, например MySQL Workbench, поэтому вам просто нужно вручную удалить эти столбцы для сгенерированного оператора и скопировать его на ваш SQL script.

В MySQL Workbench способ его создания:

Щелкните правой кнопкой мыши по таблице → отправьте в редактор Sql → Выбрать все выражение.

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 в запросах, которые вы создаете.

1

Если это всегда один и тот же столбец, то вы можете создать представление, которое не имеет его в нем.

В противном случае, я так не думаю.

-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]);
  • 0
    Это может быть здорово, но это не отвечает на вопрос: он не спрашивал о php, и вы не предоставляете оператор выбора или результат того, что он хочет, а только массив php, содержащий желаемые столбцы.
  • 2
    -1. Это не код SQL, и здесь нет SELECT - слово даже не встречается ни разу.
Показать ещё 2 комментария
-4

Выберите * - это антиспам SQL. Он не должен использоваться в производственном коде по многим причинам, включая:

Для обработки требуется немного больше времени. Когда дела идут миллионы раз, эти крошечные биты могут иметь значение. Медленная база данных, где медленность вызвана этим типом неаккуратного кодирования, - это самый сложный способ настройки производительности.

Это означает, что вы, вероятно, отправляете больше данных, чем вам нужно, что вызывает как узкие места на сервере, так и сети. Если у вас есть внутреннее соединение, вероятность отправки большего количества данных, чем вам нужно, составляет 100%.

Это вызывает проблемы обслуживания, особенно когда вы добавили новые столбцы, которые вы не видите везде. Кроме того, если у вас есть новый столбец, вам может понадобиться что-то сделать для интерфейса, чтобы определить, что делать с этим столбцом.

Он может разорвать представления (я знаю, что это правда на сервере SQl, это может быть или не быть истинным в mysql).

Если кто-то достаточно глуп, чтобы перестроить таблицы со столбцами в порядке differnt (который вы не должны делать, но это происходит все время), всевозможные коды могут сломаться. Например, код для вставки, например, когда вы помещаете город в поле address_3 becasue без указания, база данных может идти только по порядку столбцов. Это довольно плохо, когда типы данных меняются, но хуже, когда обменные столбцы имеют один и тот же тип данных, потому что вы можете пойти на то, чтобы вставлять плохие данные, которые являются беспорядком для очистки. Вам нужно заботиться о целостности данных.

Если он используется во вставке, он сломает вставку, если новый столбец будет добавлен в одну таблицу, а не другую.

Он может сломать триггеры. Проблемы с триггером могут быть трудно диагностировать.

Добавьте все это против времени, необходимого для добавления в имена столбцов (черт возьми, вы даже можете иметь интерфейс, который позволяет перетаскивать имена столбцов (я знаю, что я делаю в SQL Server, я бы поспорил, что есть некоторые способы сделать это - это инструмент, который вы используете для написания запросов mysql.) См. "Я могу вызвать проблемы с обслуживанием, я могу вызвать проблемы с производительностью, и я могу вызвать проблемы с целостностью данных, но эй, я сохранил пять минут времени разработки". На самом деле просто укажите нужные столбцы.

Я также предлагаю вам прочитать эту книгу: http://www.amazon.com/SQL-Antipatterns-Programming-Pragmatic-Programmers-ebook/dp/B00A376BB2/ref=sr_1_1?s=digital-text&amp, то есть = UTF-8 & QID = 1389896688 & ср = 1-1 & ключевые слова = SQL + antipatterns

Ещё вопросы

Сообщество Overcoder
Наверх
Меню