Question

J'essaie d'utiliser une instruction select pour obtenir toutes les colonnes d'une certaine table MySQL sauf une.Existe-t-il un moyen simple de procéder ?

MODIFIER:Il y a 53 colonnes dans ce tableau (PAS MA CONCEPTION)

Était-ce utile?

La solution

En fait, il existe un moyen, vous devez bien sûr avoir les autorisations pour faire cela...

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;

Remplacement <table>, <database> and <columns_to_omit>

Autres conseils

Dans les définitions MySQL (manuelles), cela n'existe pas.Mais si vous avez un très grand nombre de colonnes col1, ..., col100, les éléments suivants peuvent être utiles :

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

Une vue fonctionnerait-elle mieux dans ce cas ?

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

Tu peux faire:

SELECT column1, column2, column4 FROM table WHERE whatever

sans obtenir la colonne 3, mais peut-être cherchiez-vous une solution plus générale ?

Si vous cherchez à exclure la valeur d'un champ, par ex.pour des problèmes de sécurité/informations sensibles, vous pouvez récupérer cette colonne comme nulle.

par exemple.

SELECT *, NULL AS salary FROM users

À ma connaissance, il n'y en a pas.Vous pouvez faire quelque chose comme :

SELECT col1, col2, col3, col4 FROM tbl

et choisissez manuellement les colonnes souhaitées.Cependant, si vous voulez beaucoup de colonnes, vous souhaiterez peut-être simplement faire :

SELECT * FROM tbl 

et ignorez simplement ce que vous ne voulez pas.

Dans votre cas particulier, je suggérerais :

SELECT * FROM tbl

sauf si vous voulez seulement quelques colonnes.Si vous ne voulez que quatre colonnes, alors :

SELECT col3, col6, col45, col 52 FROM tbl

ce serait bien, mais si vous voulez 50 colonnes, alors tout code qui rend la requête deviendrait (trop ?) difficile à lire.

En essayant les solutions de @Mahomedalid et @Junaid, j'ai trouvé un problème.J'ai donc pensé à le partager.Si le nom de la colonne comporte des espaces ou des tirets comme l'enregistrement, la requête échouera.La solution de contournement simple consiste à utiliser un backtick autour des noms de colonnes.La requête modifiée est ci-dessous

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;

Si la colonne que vous ne souhaitez pas sélectionner contient une quantité massive de données et que vous ne souhaitez pas l'inclure en raison de problèmes de vitesse et que vous sélectionnez souvent les autres colonnes, je vous suggère de créer une nouvelle table. avec le champ que vous ne sélectionnez généralement pas avec une clé de la table d'origine et supprimez le champ de la table d'origine.Rejoignez les tables lorsque ce champ supplémentaire est réellement requis.

Vous pourriez utiliser DÉCRIRE ma_table et utilisez les résultats pour générer dynamiquement l’instruction SELECT.

Mon principal problème réside dans le nombre de colonnes que je reçois lorsque je joins des tables.Bien que ce ne soit pas la réponse à votre question (comment sélectionner toutes les colonnes sauf certaines un tableau), je pense qu'il convient de mentionner que vous pouvez spécifier table. pour obtenir toutes les colonnes d'une table particulière, au lieu de simplement spécifier .

Voici un exemple de la façon dont cela pourrait être très 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') )

Le résultat est toutes les colonnes de la table des utilisateurs et deux colonnes supplémentaires qui ont été jointes à partir de la méta-table.

J'ai aimé la réponse de @Mahomedalid en plus de ce fait informé dans le commentaire de @Bill Karwin.L'éventuel problème soulevé par @Jan Koritak C'est vrai, j'ai été confronté à cela, mais j'ai trouvé une astuce pour cela et je veux juste la partager ici pour toute personne confrontée à ce problème.

nous pouvons remplacer la fonction REPLACE par la clause Where dans la sous-requête de l'instruction Prepared comme ceci :

Utiliser le nom de ma table et de ma colonne

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;

Donc, cela va exclure uniquement le champ id mais non company_id

J'espère que cela aidera tous ceux qui recherchent une solution.

Salutations

Il est recommandé de spécifier les colonnes que vous interrogez même si vous interrogez toutes les colonnes.

Je vous suggère donc d'écrire le nom de chaque colonne dans la déclaration (en excluant celle dont vous ne voulez pas).

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

FROM table

Fais juste

SELECT * FROM table WHERE whatever

Déposez ensuite la colonne dans votre langage de programmation préféré :php

while (($data = mysql_fetch_array($result, MYSQL_ASSOC)) !== FALSE) {
   unset($data["id"]);
   foreach ($data as $k => $v) { 
      echo"$v,";
   }      
}

Je suis d'accord avec la solution "simple" consistant à répertorier toutes les colonnes, mais cela peut être fastidieux et les fautes de frappe peuvent entraîner une perte de temps considérable.J'utilise une fonction "getTableColumns" pour récupérer les noms de mes colonnes pouvant être collées dans une requête.Il ne me reste plus qu'à supprimer ceux dont je ne veux pas.

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;

Votre résultat renvoie une chaîne délimitée par des virgules, par exemple...

col1, col2, col3, col4,...col53

Je suis d'accord que ce n'est pas suffisant pour Select *, si celui dont vous n'avez pas besoin, comme mentionné ailleurs, est un BLOB, vous ne voulez pas que cette surcharge s'infiltre.

je créerais un voir avec les données requises, vous pouvez alors Select * dans le confort - si le logiciel de base de données les prend en charge.Sinon, placez les énormes données dans un autre tableau.

Au début, je pensais que vous pouviez utiliser des expressions régulières, mais au fur et à mesure que je lisais le Documentation MYSQL il semble que vous ne puissiez pas.Si j'étais vous, j'utiliserais un autre langage (tel que PHP) pour générer une liste de colonnes que vous souhaitez obtenir, la stockerais sous forme de chaîne, puis l'utiliserais pour générer le SQL.

Je le voulais aussi, alors j'ai créé une fonction à la place.

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)."`";
    }
}

Alors, comment ça marche, c'est que vous entrez dans le tableau, puis dans une colonne dont vous ne voulez pas ou comme dans un tableau :array("id", "nom", "quelle que soit la colonne")

Donc, dans select, vous pouvez l'utiliser comme ceci :

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

ou

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

D'accord sur la réponse de @Mahomedalid.Mais je ne voulais pas faire quelque chose comme une déclaration préparée et je ne voulais pas taper tous les champs.Donc, ce que j'avais était une solution idiote.Accédez à la table dans phpmyadmin->sql->select, le remplacement de la copie de la requête est effectué !:)

Bien que je sois d'accord avec la réponse de Thomas (+1 ;)), j'aimerais ajouter une mise en garde : je suppose que la colonne que vous ne le faites pas Le souhait ne contient pratiquement aucune donnée.S'il contient d'énormes quantités de texte, de blobs XML ou binaires, prenez le temps de sélectionner chaque colonne individuellement.Sinon, votre performance en souffrira.Acclamations!

Oui, même si les E/S peuvent être élevées selon le tableau, voici une solution de contournement que j'ai trouvée.

Select *
into #temp
from table

alter table #temp drop column column_name

Select *
from #temp

La réponse publiée par Mahomedalid a un petit problème :

À l'intérieur du code de fonction de remplacement remplaçait "<columns_to_delete>," par "", ce remplacement pose un problème si le champ à remplacer est le dernier de la chaîne de concatérisation car le dernier n'a pas le caractère virgule "," et n'est pas supprimé de la chaîne.

Ma proposition:

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

Remplacement <table>, <database> et `

La colonne supprimée est remplacée par la chaîne "FIELD_REMOVED". Dans mon cas, cela fonctionne car j'essayais de sauvegarder la mémoire.(Le champ que je supprimais est un BLOB d'environ 1 Mo)

Sur la base de la réponse @Mahomedalid, j'ai apporté quelques améliorations pour prendre en charge "sélectionner toutes les colonnes sauf certaines dans 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;

Si vous avez beaucoup de colonnes, utilisez ce SQL pour modifier group_concat_max_len

SET @@group_concat_max_len = 2048;

Peut-être ai-je une solution à Jan Koritak a souligné une divergence

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

Tableau :

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

================================

Résultat de la requête :

'SELECT name_eid,sal FROM employee'

S'il s'agit toujours de la même colonne, vous pouvez créer une vue qui ne la contient pas.

Sinon non, je ne pense pas.

Vous pouvez utiliser SQL pour générer du SQL si vous le souhaitez et évaluer le SQL qu'il produit.Il s'agit d'une solution générale car elle extrait les noms de colonnes du schéma d'information.Voici un exemple de la ligne de commande Unix.

Remplacement

  • MYSQL avec votre commande mysql
  • TABLE avec le nom de la table
  • EXCLUDEDFIELD avec le nom du champ exclu
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

Vous n'aurez en réalité besoin d'extraire les noms de colonnes de cette manière qu'une seule fois pour construire la liste de colonnes excluant cette colonne, puis d'utiliser simplement la requête que vous avez construite.

Donc quelque chose comme :

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)

Vous pouvez désormais réutiliser le $column_list chaîne dans les requêtes que vous construisez.

Je voudrais ajouter un autre point de vue afin de résoudre ce problème, surtout si vous avez un petit nombre de colonnes à supprimer.

Vous pouvez utiliser un outil de base de données comme Établi MySQL afin de générer l'instruction select pour vous, il vous suffit donc de supprimer manuellement ces colonnes pour l'instruction générée et de la copier dans votre script SQL.

Dans MySQL Workbench, la façon de le générer est la suivante :

Faites un clic droit sur le tableau -> envoyer à l'éditeur SQL -> Sélectionner toutes les instructions.

La réponse acceptée présente plusieurs lacunes.

  • Il échoue lorsque les noms de table ou de colonne nécessitent des backticks
  • Cela échoue si la colonne que vous souhaitez omettre est la dernière de la liste
  • Cela nécessite de lister le nom de la table deux fois (une fois pour la sélection et une autre pour le texte de la requête), ce qui est redondant et inutile.
  • Il peut potentiellement renvoyer des noms de colonnes dans le mauvais ordre

Tous ces problèmes peuvent être surmontés en incluant simplement des backticks dans le SEPARATOR pour votre GROUP_CONCAT et en utilisant un WHERE état au lieu de REPLACE().Pour mes besoins (et j'imagine bien d'autres), je voulais que les noms de colonnes soient renvoyés dans le même ordre qu'ils apparaissent dans le tableau lui-même.Pour y parvenir, nous utilisons ici un explicite ORDER BY clause à l'intérieur du GROUP_CONCAT() fonction:

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

Je suis assez en retard pour trouver une réponse à cela, c'est comme ça que je l'ai toujours fait et franchement, c'est 100 fois mieux et plus propre que la meilleure réponse, j'espère seulement que quelqu'un la verra.Et je trouve ça 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 * est un anti-modèle SQL.Il ne doit pas être utilisé dans le code de production pour de nombreuses raisons, notamment :

Le traitement prend un peu plus de temps.Lorsque les choses sont exécutées des millions de fois, ces minuscules éléments peuvent avoir leur importance.Une base de données lente, dont la lenteur est causée par ce type de codage bâclé, est la forme la plus difficile à régler en termes de performances.

Cela signifie que vous envoyez probablement plus de données que nécessaire, ce qui provoque des goulots d'étranglement sur le serveur et le réseau.Si vous disposez d’une jointure interne, les chances d’envoyer plus de données que nécessaire sont de 100 %.

Cela pose des problèmes de maintenance, notamment lorsque vous avez ajouté de nouvelles colonnes que vous ne souhaitez pas voir partout.De plus, si vous avez une nouvelle colonne, vous devrez peut-être faire quelque chose sur l'interface pour déterminer quoi faire avec cette colonne.

Cela peut casser les vues (je sais que cela est vrai dans le serveur SQL, cela peut ou non être vrai dans MySQL).

Si quelqu'un est assez idiot pour reconstruire les tables avec les colonnes dans un ordre différent (ce que vous ne devriez pas faire mais cela arrive tout le temps), toutes sortes de codes peuvent échouer.Notamment du code pour une insertion par exemple où du coup vous mettez la ville dans le champ adresse_3 car sans préciser, la base de données ne peut aller que dans l'ordre des colonnes.C'est déjà assez grave lorsque les types de données changent, mais pire lorsque les colonnes échangées ont le même type de données, car vous pouvez parfois insérer de mauvaises données qui sont un gâchis à nettoyer.Vous devez vous soucier de l’intégrité des données.

S'il est utilisé dans une insertion, l'insertion sera interrompue si une nouvelle colonne est ajoutée dans une table mais pas dans l'autre.

Cela pourrait casser les déclencheurs.Les problèmes déclencheurs peuvent être difficiles à diagnostiquer.

Additionnez tout cela au temps qu'il faut pour ajouter les noms de colonnes (bon sang, vous pouvez même avoir une interface qui vous permet de faire glisser les noms de colonnes (je sais que je le fais dans SQL Server, je parierais qu'il existe un moyen de do this est un outil que vous utilisez pour écrire des requêtes MySQL.) Voyons : "Je peux causer des problèmes de maintenance, je peux causer des problèmes de performances et je peux causer des problèmes d'intégrité des données, mais bon, j'ai économisé cinq minutes de temps de développement." dans les colonnes spécifiques souhaitées.

Je vous suggère également de lire ce livre :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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top