Domanda

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?

MODIFICARE:Ci sono 53 colonne in questa tabella (NON IL MIO DESIGN)

È stato utile?

Soluzione

In realtà esiste un modo, ovviamente è necessario avere i permessi 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>

Altri suggerimenti

Nelle definizioni mysql (manuale) non esiste nulla del genere.Ma se hai un numero davvero elevato di colonne col1, ..., col100, può essere utile quanto segue:

mysql> CREATE TEMPORARY TABLE temp_tb SELECT * FROM orig_tb;
mysql> ALTER TABLE temp_tb DROP col_x;
mysql> SELECT * FROM temp_tb;

Una vista 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 la colonna3, anche se forse stavi cercando una soluzione più generale?

Se stai cercando di escludere il valore di un campo, ad es.per problemi di sicurezza/informazioni sensibili, puoi recuperare quella colonna come null.

per esempio.

SELECT *, NULL AS salary FROM users

Per quanto ne so, non c'è.Puoi fare qualcosa come:

SELECT col1, col2, col3, col4 FROM tbl

e scegli manualmente le colonne che desideri.Tuttavia, se desideri molte colonne, potresti semplicemente voler fare un:

SELECT * FROM tbl 

e ignora semplicemente 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 rende la query diventerebbe (troppo?) difficile da leggere.

Mentre provavo le soluzioni di @Mahomedalid e @Junaid ho riscontrato un problema.Quindi ho pensato di condividerlo.Se il nome della colonna contiene spazi o trattini come check-in, la query avrà esito negativo.La soluzione semplice consiste nell'utilizzare il backtick attorno ai nomi delle colonne.La query modificata è riportata 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 vuoi selezionare contiene un'enorme quantità di dati e non vuoi includerla a causa di problemi di velocità e selezioni spesso le altre colonne, ti suggerisco di creare una nuova tabella con l'unico campo che di solito non selezioni con una chiave per la tabella originale e rimuovi il campo dalla tabella originale.Unisciti alle tabelle quando quel campo aggiuntivo è effettivamente richiesto.

Potresti usare DESCRIVI la mia_tabella e utilizzare i risultati per generare dinamicamente l'istruzione SELECT.

Il mio problema principale sono le numerose colonne che ottengo quando unisco le tabelle.Anche se questa non è la risposta alla tua domanda (come selezionare tutte le colonne tranne alcune da uno tabella), penso che valga la pena ricordare che è possibile specificare table. per ottenere tutte le colonne da una tabella particolare, invece di limitarsi a specificarle .

Ecco un esempio di come ciò potrebbe essere molto utile:

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

Il risultato sono tutte le colonne della tabella utenti e due colonne aggiuntive unite dalla meta tabella.

Mi è piaciuta la risposta di @Mahomedalid oltre a questo fatto informato nel commento di @Bill Karwin.Il possibile problema sollevato da @Jan Koritak è vero, l'ho affrontato, ma ho trovato un trucco e voglio condividerlo qui per chiunque si trovi ad affrontare il problema.

possiamo sostituire la funzione REPLACE con la clausola where nella sottoquery dell'istruzione preparata in questo modo:

Usando il nome della mia 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 no company_id

Spero che questo possa aiutare chiunque cerchi una soluzione.

Saluti

È buona norma specificare le colonne su cui eseguire la query anche se si eseguono query su tutte le colonne.

Quindi ti suggerirei di scrivere il nome di ciascuna colonna nell'istruzione (esclusa quella che non desideri).

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

Sono d'accordo con la soluzione "semplice" di elencare tutte le colonne, ma questo può essere gravoso e gli errori di battitura possono causare molto tempo sprecato.Utilizzo una funzione "getTableColumns" per recuperare i nomi delle mie colonne adatte per incollarle in una query.Quindi tutto quello 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

Sono d'accordo che non è sufficiente Select *, se quello che non ti serve, come menzionato altrove, è un BLOB, non vuoi che si insinuino quelle spese generali.

Vorrei creare un visualizzazione con i dati richiesti, allora puoi Select * in tutta comodità, se il software del database li supporta.Altrimenti, inserisci i dati enormi in un'altra tabella.

All'inizio pensavo che avresti potuto usare le espressioni regolari, ma mentre leggevo il file Documenti MYSQL sembra che tu non possa.Se fossi in te, utilizzerei un altro linguaggio (come PHP) per generare un elenco di colonne che desideri ottenere, memorizzarlo come una stringa e quindi utilizzarlo per generare l'SQL.

Lo volevo anch'io, 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, inserisci la tabella, quindi una colonna che non desideri o come in un array:array("id","nome","qualunque colonna")

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

Concordo sulla risposta di @Mahomedalid.Ma non volevo fare qualcosa come una dichiarazione preparata e non volevo digitare tutti i campi.Quindi quella che avevo era una soluzione sciocca.Vai alla tabella in phpmyadmin->sql->seleziona, scarica la copia della query, sostituisci e fai!:)

Anche se sono d'accordo con la risposta di Thomas (+1 ;)), vorrei aggiungere l'avvertenza che assumerò la colonna che tu non wish contiene pochissimi dati.Se contiene enormi quantità di testo, XML o BLOB binari, prenditi il ​​tempo necessario per selezionare ciascuna colonna individualmente.Altrimenti le tue prestazioni ne risentiranno.Saluti!

Sì, anche se l'I/O può essere elevato a seconda della tabella, ecco una soluzione che ho trovato.

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

La risposta pubblicata da Mahomedalid presenta un piccolo problema:

Il codice della funzione di sostituzione interna veniva sostituito "<columns_to_delete>," by "", questa sostituzione presenta un problema se il campo da sostituire è l'ultimo nella stringa concatenata poiché l'ultimo non contiene il carattere virgola "," e non viene rimosso dalla 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 viene sostituita dalla stringa "FIELD_REMOVED" nel mio caso funziona perché stavo cercando di proteggere la memoria.(Il campo che stavo rimuovendo è un BLOB di circa 1 MB)

Sulla base della risposta di @Mahomedalid, ho apportato alcuni miglioramenti per supportare "seleziona 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 molte colonne, usa questo sql per cambiare group_concat_max_len

SET @@group_concat_max_len = 2048;

Forse ho una soluzione Quella di Jan Koritak ha sottolineato la discrepanza

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 contenga.

Altrimenti no, non credo.

Se lo desideri, puoi utilizzare SQL per generare SQL e valutare l'SQL che produce.Questa è una soluzione generale poiché estrae i nomi delle colonne dallo schema delle informazioni.Ecco un esempio dalla riga di comando Unix.

Sostituendo

  • MYSQL con il tuo comando mysql
  • TABLE con il nome della tabella
  • EXCLUDEDFIELD con nome del campo escluso
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

In realtà dovrai estrarre i nomi delle colonne in questo modo solo una volta per costruire l'elenco delle colonne esclusa quella colonna, quindi utilizzare semplicemente la query che hai costruito.

Quindi qualcosa del tipo:

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 il file $column_list string nelle query costruite.

Vorrei aggiungere un altro punto di vista per risolvere questo problema, specialmente se hai un numero limitato di colonne da rimuovere.

Potresti usare 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 con il tasto destro sulla tabella -> invia a SQL Editor -> Seleziona tutte le istruzioni.

La risposta accettata presenta diversi difetti.

  • Fallisce laddove i nomi di tabella o colonna richiedono apici inversi
  • Fallisce se la colonna che vuoi omettere è l'ultima nell'elenco
  • Richiede l'elenco del nome della tabella due volte (una volta per la selezione e un'altra per il testo della query), il che è ridondante e non necessario
  • Può potenzialmente restituire nomi di colonne nel file ordine sbagliato

Tutti questi problemi possono essere risolti semplicemente includendo i backtick nel file SEPARATOR per il tuo GROUP_CONCAT e utilizzando a WHERE condizione invece di REPLACE().Per i miei scopi (e immagino molti altri) volevo che i nomi delle colonne fossero restituiti nello stesso ordine in cui appaiono nella tabella stessa.Per raggiungere questo obiettivo, qui utilizziamo un esplicitamente ORDER BY clausola all'interno del 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 in ritardo nel dare una risposta a questa domanda, metti questo è il modo in cui l'ho sempre fatto e, francamente, è 100 volte migliore e più accurato della risposta migliore, spero solo che qualcuno la veda.E trovarlo 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 * è un antipattern SQL.Non dovrebbe 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 dettagli possono avere importanza.Un database lento in cui la lentezza è causata da questo tipo di codifica sciatta è il tipo più difficile da ottimizzare le prestazioni.

Significa che probabilmente stai inviando più dati del necessario, il che causa colli di bottiglia sia sul server che sulla rete.Se disponi di un inner join, le probabilità di inviare più dati del necessario 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 sull'interfaccia per determinare cosa fare con quella colonna.

Può interrompere le visualizzazioni (so che questo è vero nel server SQL, può essere vero o meno in mysql).

Se qualcuno è così sciocco da ricostruire le tabelle con le colonne in un ordine diverso (cosa che non dovresti fare ma succede sempre), tutti i tipi di codice possono rompersi.Soprattutto il codice per un inserimento, ad esempio dove all'improvviso si inserisce la città nel campo indirizzo_3 perché senza specificarlo, il database può seguire solo l'ordine delle colonne.Questo è già abbastanza grave quando i tipi di dati cambiano, ma è peggio quando le colonne scambiate hanno lo stesso tipo di dati perché a volte puoi inserire dati errati che sono un disastro da ripulire.Devi preoccuparti dell'integrità dei dati.

Se viene utilizzato in un inserimento, interromperà l'inserimento se viene aggiunta una nuova colonna in una tabella ma non nell'altra.

Potrebbe rompere i trigger.I problemi scatenanti possono essere difficili da diagnosticare.

Somma tutto questo rispetto al tempo necessario per aggiungere i nomi delle colonne (diamine, potresti anche avere un'interfaccia che ti permette di trascinare i nomi delle colonne (so di farlo in SQL Server, scommetto che c'è un modo per fai 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." In realtà ho appena detto nelle colonne specifiche che desideri.

Ti consiglio 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&keywords=sql+antipatterns

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top