Sto cercando di utilizzare un'istruzione select per ottenere tutte le colonne da una determinata tabella MySQL tranne una. C'è un modo semplice per fare questo?
EDIT: ci sono 53 colonne in questa tabella (NON IL MIO DESIGN)
Sto cercando di utilizzare un'istruzione select per ottenere tutte le colonne da una determinata tabella MySQL tranne una. C'è un modo semplice per fare questo?
EDIT: ci sono 53 colonne in questa tabella (NON IL MIO DESIGN)
Risposte:
In realtà c'è un modo, è necessario disporre delle autorizzazioni ovviamente per farlo ...
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;
Sostituzione <table>, <database> and <columns_to_omit>
<column_name>
Nelle definizioni di mysql (manuale) non esiste nulla del genere. Ma se hai un numero davvero elevato di colonne col1
, ..., col100
può essere utile quanto segue:
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;
Un View funzionerebbe meglio in questo caso?
CREATE VIEW vwTable
as
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Tu puoi fare:
SELECT column1, column2, column4 FROM table WHERE whatever
senza ottenere column3, anche se forse stavi cercando una soluzione più generale?
Se stai cercando di escludere il valore di un campo, ad esempio per problemi di sicurezza / informazioni sensibili, puoi recuperare quella colonna come null.
per esempio
SELECT *, NULL AS salary FROM users
salary
colonna. Ma poiché viene recuperato dopo il *, sovrascrive l'originale. Non è carino, ma funziona.
Per quanto ne so, non esiste. Puoi fare qualcosa del tipo:
SELECT col1, col2, col3, col4 FROM tbl
e scegli manualmente le colonne che desideri. Tuttavia, se vuoi molte colonne, potresti semplicemente voler fare un:
SELECT * FROM tbl
e ignora ciò che non vuoi.
Nel tuo caso particolare, suggerirei:
SELECT * FROM tbl
a meno che tu non voglia solo poche colonne. Se vuoi solo quattro colonne, allora:
SELECT col3, col6, col45, col 52 FROM tbl
andrebbe bene, ma se vuoi 50 colonne, qualsiasi codice che renda la query diventerebbe (troppo?) difficile da leggere.
Durante il tentativo delle soluzioni di @Mahomedalid e @Junaid ho riscontrato un problema. Quindi ho pensato di condividerlo. Se il nome della colonna presenta spazi o trattini come il check-in, la query avrà esito negativo. La semplice soluzione consiste nell'utilizzare il backtick attorno ai nomi delle colonne. La query modificata è di seguito
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 la colonna che non volevi selezionare contenesse una grande quantità di dati e non volessi includerli a causa di problemi di velocità e selezioni spesso le altre colonne, ti suggerirei di creare una nuova tabella con l'unico campo che di solito non si seleziona con una chiave per la tabella originale e rimuovere il campo dalla tabella originale. Unisciti ai tavoli quando quel campo extra è effettivamente richiesto.
È possibile utilizzare DESCRIBE my_table e utilizzare i risultati per generare l'istruzione SELECT in modo dinamico.
Il mio problema principale sono le molte colonne che ottengo quando mi unisco alle tabelle. Sebbene questa non sia la risposta alla tua domanda (come selezionare tutte le colonne tranne alcune da una tabella), penso che valga la pena ricordare che puoi specificare di ottenere tutte le colonne da una tabella particolare, invece di specificare .table.
Ecco un esempio di come questo potrebbe essere molto utile:
seleziona utenti. *, phone.meta_value come telefono, zipcode.meta_value come codice postale dagli utenti left join user_meta come telefono on ((users.user_id = phone.user_id) AND (phone.meta_key = 'phone')) left join user_meta come codice postale on ((users.user_id = zipcode.user_id) AND (zipcode.meta_key = 'zipcode'))
Il risultato sono tutte le colonne della tabella degli utenti e due colonne aggiuntive che sono state unite dalla meta tabella.
Mi è piaciuta la risposta @Mahomedalid
oltre a questo fatto informato nel commento di @Bill Karwin
. Il possibile problema sollevato @Jan Koritak
è vero che l'ho affrontato, ma ho trovato un trucco per questo e voglio solo condividerlo qui per chiunque si trovi ad affrontare il problema.
possiamo sostituire la funzione REPLACE con la clausola where nella sottoquery dell'istruzione Prepared in questo modo:
Usando il mio nome di tabella e colonna
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;
Quindi, questo escluderà solo il campo id
ma noncompany_id
È buona norma specificare le colonne su cui si esegue la query anche se si eseguono query su tutte le colonne.
Quindi ti suggerisco di scrivere il nome di ogni colonna nell'istruzione (escluso quello che non vuoi).
SELECT
col1
, col2
, col3
, col..
, col53
FROM table
Basta fare
SELECT * FROM table WHERE whatever
Quindi rilascia la colonna nel tuo linguaggio di programmazione preferito: php
while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
unset($data["id"]);
foreach ($data as $k => $v) {
echo"$v,";
}
}
Concordo con la "semplice" soluzione di elencare tutte le colonne, ma questo può essere oneroso e gli errori di battitura possono causare un sacco di tempo sprecato. Uso una funzione "getTableColumns" per recuperare i nomi delle mie colonne adatte per incollare in una query. Quindi tutto ciò che devo fare è eliminare quelli che non voglio.
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;
Il risultato restituisce una stringa delimitata da virgole, ad esempio ...
col1, col2, col3, col4, ... col53
Concordo sul fatto che non è sufficiente Select *
, se quello di cui non hai bisogno, come menzionato altrove, è un BLOB, non vuoi avere quel sovraccarico.
Vorrei creare una vista con i dati richiesti, quindi puoi Select *
comodamente - se il software del database li supporta. Altrimenti, metti gli enormi dati in un'altra tabella.
All'inizio pensavo che avresti potuto usare espressioni regolari, ma dato che ho letto i documenti di MYSQL sembra che tu non possa farlo. Se fossi in te userei un altro linguaggio (come PHP) per generare un elenco di colonne che si desidera ottenere, memorizzarlo come una stringa e quindi utilizzarlo per generare l'SQL.
Volevo anche questo, quindi ho creato una funzione.
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)."`";
}
}
Quindi, come funziona è che inserisci la tabella, quindi una colonna che non vuoi o come in un array: array ("id", "name", "whatevercolumn")
Quindi in select potresti usarlo in questo modo:
mysql_query("SELECT ".$db->getColsExcept('table',array('id','bigtextcolumn'))." FROM table");
o
mysql_query("SELECT ".$db->getColsExcept('table','bigtextcolumn')." FROM table");
Sono d'accordo con la risposta di @ Mahomedalid, ma non volevo fare qualcosa di simile a una dichiarazione preparata e non volevo digitare tutti i campi, quindi quella che avevo era una soluzione sciocca.
Vai alla tabella in phpmyadmin-> sql-> select, scarica la query: copia, sostituisci e fatto! :)
Mentre sono d'accordo con la risposta di Thomas (+1;)), vorrei aggiungere l'avvertenza che suppongo che la colonna che non vuoi contiene quasi nessun dato. Se contiene enormi quantità di BLOB di testo, XML o binari, prenditi il tempo necessario per selezionare ciascuna colonna singolarmente. La tua esibizione subirà diversamente. Saluti!
La risposta pubblicata da Mahomedalid ha un piccolo problema:
All'interno del codice di funzione di sostituzione stava sostituendo " <columns_to_delete>,
" con "", questa sostituzione ha un problema se il campo da sostituire è l'ultimo nella stringa concat a causa dell'ultimo non ha la virgola "," e non viene rimosso da la stringa.
La mia 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>');
Sostituzione <table>
, <database>
e `
La colonna rimossa è sostituita dalla stringa "FIELD_REMOVED" nel mio caso funziona perché stavo cercando di salvare la memoria. (Il campo che stavo rimuovendo è un BLOB di circa 1 MB)
Sulla base della risposta @Mahomedalid, ho apportato alcuni miglioramenti per supportare "selezionare tutte le colonne tranne alcune in 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 hai molti cols, usa questo sql per cambiare group_concat_max_len
SET @@group_concat_max_len = 2048;
Forse ho una soluzione alla discrepanza rilevata di 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' );
Tavolo :
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
================================
Risultato della query:
'SELECT name_eid,sal FROM employee'
Se è sempre la stessa colonna, puoi creare una vista che non la contiene.
Altrimenti no, non credo.
È possibile utilizzare SQL per generare SQL se lo si desidera e valutare l'SQL che produce. Questa è una soluzione generale in quanto estrae i nomi delle colonne dallo schema delle informazioni. Ecco un esempio dalla riga di comando di Unix.
sostituendo
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
Avrai davvero bisogno di estrarre i nomi delle colonne in questo modo solo una volta per costruire l'elenco delle colonne escluso quella colonna, e quindi usare solo la query che hai creato.
Quindi qualcosa come:
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)
Ora puoi riutilizzare la $column_list
stringa nelle query che costruisci.
Vorrei aggiungere un altro punto di vista per risolvere questo problema, specialmente se hai un piccolo numero di colonne da rimuovere.
Puoi utilizzare uno strumento DB come MySQL Workbench per generare l'istruzione select per te, quindi devi solo rimuovere manualmente quelle colonne per l'istruzione generata e copiarla nel tuo script SQL.
In MySQL Workbench il modo per generarlo è:
Fare clic destro sulla tabella -> invia a SQL Editor -> Seleziona tutto istruzione.
La risposta accettata presenta diverse carenze.
Tutti questi problemi possono essere superati semplicemente includendo i backtick nel SEPARATOR
tuo GROUP_CONCAT
e usando una WHERE
condizione anziché REPLACE()
. Per i miei scopi (e immagino molti altri), volevo che i nomi delle colonne fossero restituiti nello stesso ordine in cui compaiono nella tabella stessa. Per raggiungere questo obiettivo, qui utilizziamo una ORDER BY
clausola esplicita all'interno della GROUP_CONCAT()
funzione:
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';
Sono abbastanza tardi nel trovare una risposta per questo, metto questo è il modo in cui l'ho sempre fatto e francamente, è 100 volte migliore e più pulito della migliore risposta, spero solo che qualcuno lo vedrà. E lo trova utile
//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
dichiarazione qui: la parola non compare nemmeno una volta.
Seleziona * è un antipattern SQL. Non deve essere utilizzato nel codice di produzione per molte ragioni, tra cui:
L'elaborazione richiede un po 'più di tempo. Quando le cose vengono eseguite milioni di volte, quei piccoli pezzi possono avere importanza. Un database lento in cui la lentezza è causata da questo tipo di codice sciatto è il tipo più difficile da ottimizzare.
Significa che probabilmente stai inviando più dati del necessario, il che causa colli di bottiglia sia del server che della rete. Se si dispone di un join interno, le probabilità di inviare più dati di quelli necessari sono del 100%.
Causa problemi di manutenzione soprattutto quando hai aggiunto nuove colonne che non vuoi vedere ovunque. Inoltre, se hai una nuova colonna, potresti dover fare qualcosa all'interfaccia per determinare cosa fare con quella colonna.
Può spezzare le viste (so che questo è vero nel server SQl, può o meno essere vero in mysql).
Se qualcuno è abbastanza sciocco da ricostruire le tabelle con le colonne in un ordine diverso (cosa che non dovresti fare ma succede tutto il tempo), ogni tipo di codice può rompersi. Soprattutto codice per un inserto, ad esempio dove improvvisamente stai inserendo la città nel campo address_3 perché senza specificare, il database può andare solo sull'ordine delle colonne. Questo è abbastanza grave quando i tipi di dati cambiano, ma peggio ancora quando le colonne scambiate hanno lo stesso tipo di dati perché puoi andare a volte inserendo dati errati che è un disastro da pulire. Devi preoccuparti dell'integrità dei dati.
Se viene utilizzato in un inserto, interromperà l'inserimento se una nuova colonna viene aggiunta in una tabella ma non nell'altra.
Potrebbe rompere i trigger. I problemi di innesco possono essere difficili da diagnosticare.
Aggiungi tutto questo contro il tempo necessario per aggiungere i nomi delle colonne (diamine potresti anche avere un'interfaccia che ti permetta di trascinare sopra i nomi delle colonne (so che lo faccio in SQL Server, scommetto che c'è un modo per fare questo è uno strumento che usi per scrivere query mysql.) Vediamo, "Posso causare problemi di manutenzione, posso causare problemi di prestazioni e posso causare problemi di integrità dei dati, ma ehi, ho risparmiato cinque minuti di tempo di sviluppo." nelle colonne specifiche che desideri.
Ti suggerisco anche di leggere questo libro: 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 & parole chiave = sql + antipattern