Estou tentando usar uma instrução select para obter todas as colunas de uma determinada tabela do MySQL, exceto uma. Existe uma maneira simples de fazer isso?
EDIT: existem 53 colunas nesta tabela (NÃO MEU DESIGN)
Estou tentando usar uma instrução select para obter todas as colunas de uma determinada tabela do MySQL, exceto uma. Existe uma maneira simples de fazer isso?
EDIT: existem 53 colunas nesta tabela (NÃO MEU DESIGN)
Respostas:
Na verdade, existe uma maneira, você precisa ter permissões, é claro, para fazer isso ...
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;
Substituindo <table>, <database> and <columns_to_omit>
<column_name>
Nas definições do mysql (manual) não existe. Mas se você tiver um número realmente grande de colunas col1
, ... col100
, o seguinte poderá ser útil:
DROP TABLE IF EXISTS temp_tb;
CREATE TEMPORARY TABLE ENGINE=MEMORY temp_tb SELECT * FROM orig_tb;
ALTER TABLE temp_tb DROP col_x;
SELECT * FROM temp_tb;
DROP TABLE IF EXISTS temp_tb;
CREATE TEMPORARY TABLE temp_tb ENGINE=MEMORY (SELECT * FROM orig_tb);
caso contrário, ele é salvo no disco por padrão e sobrevive à reinicialização do servidor. ( obrigado )
Um View funcionaria melhor nesse caso?
CREATE VIEW vwTable
as
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Você pode fazer:
SELECT column1, column2, column4 FROM table WHERE whatever
sem obter a coluna3, embora talvez você estivesse procurando uma solução mais geral?
Se você deseja excluir o valor de um campo, por exemplo, por questões de segurança / informações confidenciais, é possível recuperar essa coluna como nula.
por exemplo
SELECT *, NULL AS salary FROM users
salary
coluna. Mas, como é recuperado após o *, ele substitui o original. Não é bonito, mas funciona.
Que eu saiba, não existe. Você pode fazer algo como:
SELECT col1, col2, col3, col4 FROM tbl
e escolha manualmente as colunas que deseja. No entanto, se você quiser muitas colunas, poderá fazer:
SELECT * FROM tbl
e apenas ignore o que você não quer.
No seu caso particular, eu sugeriria:
SELECT * FROM tbl
a menos que você queira apenas algumas colunas. Se você deseja apenas quatro colunas, então:
SELECT col3, col6, col45, col 52 FROM tbl
seria bom, mas se você quiser 50 colunas, qualquer código que faça a consulta se tornará (também?) difícil de ler.
Ao tentar as soluções de @Mahomedalid e @Junaid, encontrei um problema. Então, pensei em compartilhá-lo. Se o nome da coluna tiver espaços ou hífens, como o check-in, a consulta falhará. A solução simples é usar backtick em torno dos nomes das colunas. A consulta modificada está abaixo
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;
Se a coluna que você não deseja selecionar continha uma grande quantidade de dados e não os incluía devido a problemas de velocidade e você seleciona as outras colunas frequentemente, sugiro que você crie uma nova tabela com o campo que você normalmente não seleciona com uma chave para a tabela original e remova o campo da tabela original. Junte-se às tabelas quando esse campo extra for realmente necessário.
Você pode usar DESCRIBE minha_tabela e usar os resultados para gerar a instrução SELECT dinamicamente.
Meu principal problema são as muitas colunas que recebo ao ingressar nas tabelas. Embora essa não seja a resposta para sua pergunta (como selecionar todas as colunas, exceto algumas de uma tabela), acho que vale a pena mencionar que você pode especificar para obter todas as colunas de uma tabela específica, em vez de apenas especificar .table.
Aqui está um exemplo de como isso pode ser muito útil:
selecione users. *, phone.meta_value como phone, zipcode.meta_value como zipcode dos usuários deixou juntar user_meta como telefone on ((users.user_id = phone.user_id) AND (phone.meta_key = 'phone')) deixou unir user_meta como CEP on ((users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode'))
O resultado são todas as colunas da tabela de usuários e duas colunas adicionais que foram unidas a partir da meta-tabela.
Eu gostei da resposta de @Mahomedalid
além deste fato informado no comentário de @Bill Karwin
. O possível problema levantado por @Jan Koritak
é verdade. Enfrentei isso, mas encontrei um truque para isso e só quero compartilhá-lo aqui para qualquer um que esteja enfrentando o problema.
podemos substituir a função REPLACE pela cláusula where na subconsulta da instrução Prepared como esta:
Usando meu nome de tabela e coluna
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;
Então, isso vai excluir apenas o campo, id
mas nãocompany_id
É uma boa prática especificar as colunas que você está consultando, mesmo se você consultar todas as colunas.
Então, eu sugiro que você escreva o nome de cada coluna na declaração (excluindo a que você não deseja).
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Apenas faça
SELECT * FROM table WHERE whatever
Em seguida, solte a coluna na sua linguagem de programação favorita: php
while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
unset($data["id"]);
foreach ($data as $k => $v) {
echo"$v,";
}
}
Concordo com a solução "simples" de listar todas as colunas, mas isso pode ser oneroso e erros de digitação podem causar muito tempo perdido. Eu uso a função "getTableColumns" para recuperar os nomes de minhas colunas adequadas para colar em uma consulta. Então, tudo o que preciso fazer é excluir aqueles que não quero.
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;
Seu resultado retorna uma string delimitada por vírgula, por exemplo ...
col1, col2, col3, col4, ... col53
Concordo que não é suficiente Select *
, se aquele de que você não precisa, como mencionado em outro lugar, é um BLOB, você não quer que essa sobrecarga ocorra.
Eu criaria uma visualização com os dados necessários, para que você possa Select *
com conforto - se o software do banco de dados os suportar. Senão, coloque os enormes dados em outra tabela.
No começo eu pensei que você poderia usar expressões regulares, mas como eu tenho lido os documentos do MYSQL , parece que você não pode. Se eu fosse você, usaria outra linguagem (como PHP) para gerar uma lista de colunas que deseja obter, armazene-a como uma string e use-a para gerar o SQL.
Eu também queria isso, então criei uma função.
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)."`";
}
}
Então, como ele funciona é que você insere a tabela e, em seguida, uma coluna que não deseja ou como em uma matriz: array ("id", "name", "Whatevercolumn")
Então, em select, você pode usá-lo assim:
mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");
ou
mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");
Embora eu concorde com a resposta de Thomas (+1;)), gostaria de adicionar a ressalva de que assumirei que a coluna que você não deseja contém quase nenhum dado. Se ele contiver enormes quantidades de texto, xml ou blobs binários, reserve um tempo para selecionar cada coluna individualmente. Seu desempenho sofrerá de outra forma. Felicidades!
A resposta postada por Mahomedalid tem um pequeno problema:
O código da função de substituição interna estava substituindo " <columns_to_delete>,
" por "", esta substituição tem um problema se o campo a substituir for o último na sequência de concat, pois o último não possui a vírgula de caractere "," e não é removido de a corda.
Minha proposta:
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>');
Substituindo <table>
, <database>
e `
A coluna removida é substituída pela string "FIELD_REMOVED". No meu caso, isso funciona porque eu estava tentando economizar memória. (O campo que eu estava removendo é um BLOB de cerca de 1 MB)
Com base na resposta @Mahomedalid, fiz algumas melhorias para suportar "selecione todas as colunas, exceto algumas no 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;
Se você possui muitas colunas, use este sql para alterar group_concat_max_len
SET @@group_concat_max_len = 2048;
Pode ser que eu tenha uma solução para a discrepância apontada por 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' );
Mesa :
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
================================
Resultado da consulta:
'SELECT name_eid,sal FROM employee'
Se for sempre a mesma coluna, você poderá criar uma exibição que não a contém.
Caso contrário, não, acho que não.
Você pode usar o SQL para gerar o SQL, se desejar e avaliar o SQL que ele produz. Essa é uma solução geral, pois extrai os nomes das colunas do esquema de informações. Aqui está um exemplo da linha de comando do Unix.
Substituindo
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
Você realmente precisará extrair os nomes das colunas dessa maneira apenas uma vez para construir a lista de colunas excluídas dessa coluna e, em seguida, basta usar a consulta que você construiu.
Então, algo como:
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)
Agora você pode reutilizar a $column_list
string nas consultas que você constrói.
Gostaria de adicionar outro ponto de vista para resolver esse problema, especialmente se você tiver um pequeno número de colunas para remover.
Você pode usar uma ferramenta de banco de dados como o MySQL Workbench para gerar a instrução select para você; basta remover manualmente essas colunas da instrução gerada e copiá-la para o script SQL.
No MySQL Workbench, o caminho para gerá-lo é:
Clique com o botão direito do mouse na tabela -> enviar para o Sql Editor -> Selecionar todas as instruções.
A resposta aceita tem várias falhas.
Todos esses problemas podem ser superados com a simples inclusão de backticks no SEPARATOR
for your GROUP_CONCAT
e usando uma WHERE
condição em vez de REPLACE()
. Para meus propósitos (e imagino muitos outros), queria que os nomes das colunas retornassem na mesma ordem em que aparecem na própria tabela. Para conseguir isso, aqui usamos uma ORDER BY
cláusula explícita dentro da GROUP_CONCAT()
função:
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';
Estou bem atrasado em encontrar uma resposta para isso, coloque desta maneira que sempre fiz e, francamente, é 100 vezes melhor e mais organizado do que a melhor resposta, só espero que alguém o veja. E achar útil
//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
declaração aqui - a palavra nem ocorre uma vez.
Selecione * é um antipadrão SQL. Não deve ser usado no código de produção por vários motivos, incluindo:
Demora um pouco mais para processar. Quando as coisas acontecem milhões de vezes, esses pequenos pedaços podem ter importância. Um banco de dados lento em que a lentidão é causada por esse tipo de codificação superficial é o tipo mais difícil de ajustar o desempenho.
Isso significa que você provavelmente está enviando mais dados do que o necessário, o que causa gargalos no servidor e na rede. Se você tiver uma associação interna, as chances de enviar mais dados do que você precisa são de 100%.
Isso causa problemas de manutenção, especialmente quando você adiciona novas colunas que não deseja que sejam vistas em todos os lugares. Além disso, se você tiver uma nova coluna, pode ser necessário fazer algo na interface para determinar o que fazer com essa coluna.
Ele pode interromper as visualizações (eu sei que isso é verdade no servidor SQl, pode ou não ser verdade no mysql).
Se alguém for tolo o suficiente para reconstruir as tabelas com as colunas em uma ordem diferente (o que você não deve fazer, mas acontece o tempo todo), todo tipo de código pode ser quebrado. Codifique especialmente para uma inserção, por exemplo, onde de repente você está colocando a cidade no campo address_3, porque sem especificar, o banco de dados só pode seguir a ordem das colunas. Isso é ruim o suficiente quando os tipos de dados são alterados, mas pior quando as colunas trocadas têm o mesmo tipo de dados, pois você pode, por algum tempo, inserir dados ruins que são uma bagunça para limpar. Você precisa se preocupar com a integridade dos dados.
Se for usado em uma inserção, ele será interrompido se uma nova coluna for adicionada em uma tabela, mas não na outra.
Pode quebrar gatilhos. Problemas de gatilho podem ser difíceis de diagnosticar.
Adicione tudo isso contra o tempo que leva para adicionar os nomes das colunas (diabos você pode até ter uma interface que permita arrastar os nomes das colunas (eu sei que sim no SQL Server, aposto que há alguma maneira de faça isso é uma ferramenta que você usa para escrever consultas mysql.) Vamos ver: "Eu posso causar problemas de manutenção, posso causar problemas de desempenho e problemas de integridade de dados, mas ei, salvei cinco minutos de tempo de desenvolvimento." nas colunas específicas que você deseja.
Também sugiro que você leia este livro: 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 & palavras-chave = sql + antipatterns