web-dev-qa-db-fra.com

Pouvez-vous tout sélectionner, sauf 1 ou 2 champs, sans la crampe de l'écrivain?

Est-il possible, dans PLSQL, de sélectionner tous les champs d'une table à l'exception de 1 ou 2, sans avoir à spécifier les champs souhaités?

Exemple, la table employee contient les champs: 

  • identifiant
  • prénom
  • nom de famille
  • loisirs

Est-il encore possible d'écrire une requête similaire à 

select * from employee

en quittant le champ hobbies sans avoir à écrire quelque chose comme ça?

select id, firstname, lastname from employee
43
Steve
42
Yahia

Si vous voulez éviter les crampes du rédacteur, vous pouvez utiliser SQL Developer et lui demander de générer la liste des colonnes pour vous:

select column_name||','
from all_tab_columns
where table_name = 'YourTableName'

Ensuite, supprimez la ou les colonnes que vous ne voulez pas.

Vous pouvez aussi utiliser 

SELECT listagg(column_name, ',') within group (order by column_name) columns
FROM all_tab_columns
WHERE table_name = 'TABLE_NAME'
GROUP BY table_name;
37
Michael Fredrickson

Utilisez-vous Oracle 12c?

Si oui, déterminez si cela répond à vos besoins:

alter table mytable modify column undesired_col_name INVISIBLE;

Dans ce cas, la colonne undesired_col_name sera entièrement utilisable, mais elle sera exclue de toutes les instructions SELECT * et similaires (par exemple, %ROWTYPE) comme si elle n'existait pas.

19
Matthew McPeak

Un vieux fil mais, oui ... il y a un moyen de le faire dans Oracle:

with

employee(id, firstname, lastname, hobbies) as
(
  select 1, 'a', 'b', '1' from dual union 
  select 2, 'a', 'b', '2' from dual union 
  select 3, 'a', 'b', '3' from dual union 
  select 4, 'c', 'd', '3' from dual union 
  select 5, 'e', 'f', '2' from dual  
)

select * 
from employee 
pivot
( 
  max(1) -- fake  
  for (hobbies) -- put the undesired columns here
  IN () -- no values here...
) 
where 1=1 -- and your filters here...
order by id

Pour comprendre comment le PIVOT fonctionne et pourquoi il résout la question, prenons un meilleur exemple pour notre exemple de table employee:

select * 
from employee 
pivot
(
  max(id) foo,
  max(1)  bar
  for (hobbies) 
  IN ('2' as two, '3' as three)
)

Le résultat ici est: 

 PRENOM | NOM DE FAMILLE | TWO_FOO | TWO_BAR | THREE_FOO | THREE_BAR 
 c d null null 4 1 
 e f 5 1 null null 
 a b 2 1 3 1 

Le même résultat peut être obtenu avec cette requête plus facile à comprendre:

select 
  firstname,
  lastname,
  max(case when hobbies = '2' then id end) two_foo,
  max(case when hobbies = '2' then 1  end) two_bar,
  max(case when hobbies = '3' then id end) three_foo,
  max(case when hobbies = '3' then 1  end) three_bar
from employee 
group by
  firstname,
  lastname

Ainsi, la colonne hobbies n'est jamais sélectionnée, tout comme la colonne id, toutes deux spécifiées à l'intérieur du PIVOT clause. Toutes les autres colonnes sont regroupées et sélectionnées.

Revenons à la première requête. Cela fonctionne pour deux raisons:
1- vous ne perdrez aucune rangée dans le processus de regroupement car le identifiant la colonne est unique et aucune colonne n'a été spécifiée pour les agrégations; 
2- car le pivot génère N * M nouvelles colonnes, où N = nombre de valeurs de la DANS clause et M = nombre d'agrégations spécifiées. Par conséquent, ne pas avoir de filtres et cette agrégation inoffensive produira 0 * 1 = 0 nouvelles colonnes et supprimera celles spécifiées PIVOT clause, qui est juste la loisirs.


RÉPONSE AU COMMENTAIRE 1

La première ligne de cette question dit: "... sans avoir à spécifier les champs que vous voulez" . Dans toutes les autres réponses, les requêtes proposées spécifient les champs souhaités dans SÉLECTIONNER clause, sauf dans le mien, en fait. 

De plus, dans le titre de la question, on lit "... sans la crampe de l'écrivain" . Eh bien, quelle est la bonne mesure pour identifier la crampe d'un écrivain? Mon meilleur effort serait de prévoir un bon standard SQL à ce problème et de le comparer avec ma réponse. En fait, je pense que cette "norme" pourrait être quelque chose comme SELECT * NOT IN ([col1], [col2], ...)

Maintenant, je peux voir dans les deux requêtes:

  • une liste de colonnes indésirables;
  • un DANS clause;
  • une clause de trois caractères - FOR et NE PAS;

Cela signifie que vous devez écrire un peu plus dans mon approche car vous avez besoin d’une fausse agrégation et de la PIVOT clause ... mais c'est vraiment quelques caractères de plus ... 

17
Felypp Oliveira

query_generator est une fonction PL/SQL qui renvoie un select string pour une table (1er paramètre) mais en excluant certaines colonnes (2ème paramètre).

stringlist et putil.join proviennent de PL/SQL Commons .

stringlist est une simple liste de chaînes: create type StringList as table of varchar2(32767); et putil.join est simplement une fonction de jointure normale.

create or replace function quote_list(p_list in stringlist)
return stringlist as
  v_list stringlist := stringlist();
begin
  v_list.extend(p_list.last);
  for i in p_list.first .. p_list.last loop
    v_list(i) := '''' || p_list(i) || '''';
  end loop;

  return v_list;
end;
/
show errors

create or replace function query_generator(
  p_table in varchar2,
  p_exclude in stringlist
) return varchar2 as
  v_table constant varchar2(31) := upper(p_table);
  v_exclude constant varchar2(32676) :=
    upper(putil.join(quote_list(p_exclude), ','));
  v_stmt_str constant varchar2(32676) :=
    'select column_name from all_tab_columns where table_name = ''' ||
    v_table || ''' and column_name not in (' || v_exclude ||
    ') order by column_id';
  type stmt_cur_t is ref cursor;
  v_stmt_cur stmt_cur_t;
  v_column_name varchar2(31);
  v_query varchar2(32676) := 'select ';
begin
  open v_stmt_cur for v_stmt_str;

  loop
    fetch v_stmt_cur into v_column_name;
    exit when v_stmt_cur%notfound;
    v_query := v_query || lower(v_column_name) || ', ';
  end loop;

  close v_stmt_cur;

  select rtrim(v_query, ', ') into v_query from dual;

  v_query := v_query || ' from ' || p_table || ';';

  return v_query;
end;
/
show errors

Exemple d'utilisation:

exec dbms_output.put_line(query_generator('all_tables', stringlist('segment_created', 'result_cache')))
2
user272735

Ce que le PO cherchait était quelque chose comme:

SELECT * MINUS hobbies from...

La meilleure chose à faire pour éviter beaucoup de frappe (et obtenir tous les noms de colonne corrects) est d'ouvrir la description du tableau et de couper et coller tous les noms de colonne et de supprimer ceux que vous ne voulez pas, séparez les noms restants par une virgule et mettez-les sur une ligne ou deux.

C'est facile, rapide, précis et vous ne serez pas dérouté par la prochaine personne qui doit travailler sur votre code. 

2
user2785110
WITH O AS
(
SELECT 'SELECT ' || rtrim('NULL AS "Dummy",' || LISTAGG('"'||column_name || '"', ',' ) within group (ORDER BY COLUMN_NAME),',')|| ' FROM "'||TABLE_NAME||'"' AS SQL, TABLE_NAME  FROM USER_TAB_COLUMNS  GROUP BY (TABLE_NAME)
)
SELECT DBMS_XMLGEN.GETXMLTYPE ((SELECT REPLACE(SQL,',COLUMNNAME','') FROM O WHERE TABLE_NAME = 'TABLENAME')) FROM DUAL
1
clq

pour créer une vue: -

créer la vue nom_vue comme ID de sélection, prénom, nom de l'employé où ID dans ('', '', '')

remarque: - Cela ressemble à une table virtuelle dans votre base de données, mais cela peut affecter les valeurs de la table réelle.

0
deepak_giri_goswami

Les fonctions de table polymorphes Oracle 18c permettent de tout sélectionner dans une table et d’exclure une liste de colonnes:

select * from everything_but(employee, columns(hobbies));

ID   FIRSTNAME   LASTNAME
--   ---------   --------
1    John        Smith

La création de cette fonction nécessite le package ci-dessous, copié du site Web de Tim Hall https://Oracle-base.com/articles/18c/polymorphic-table-functions-18c :

CREATE OR REPLACE PACKAGE poly_pkg AS

  FUNCTION everything_but(tab IN TABLE,
                          col IN COLUMNS)
  RETURN TABLE PIPELINED
  ROW POLYMORPHIC USING poly_pkg;

  FUNCTION describe (tab IN OUT DBMS_TF.table_t,
                     col IN     dbms_tf.columns_t)
    RETURN DBMS_TF.describe_t;

END poly_pkg;
/


CREATE OR REPLACE PACKAGE BODY poly_pkg AS

  FUNCTION describe (tab IN OUT DBMS_TF.table_t,
                     col IN     dbms_tf.columns_t)
    RETURN DBMS_TF.describe_t
  AS
  BEGIN
    -- Loop through all the table columns.
    FOR i IN 1 .. tab.column.count() LOOP
      -- Loop through all the columns listed in the second parameter.
      FOR j IN 1 .. col.count() LOOP
        -- Set pass_through to true for any columns not in the exclude list.
        tab.column(i).pass_through := (tab.column(i).description.name != col(j));
        -- Exit inner loop if you find a column that shouldn't be included.
        EXIT WHEN NOT tab.column(i).pass_through;
      END LOOP;
    END LOOP;

    RETURN NULL;
  END;

END poly_pkg;
/

J'ai également créé cette fonction d'emballage pour lui donner un meilleur nom. Et créé un exemple de tableau simple.

CREATE OR REPLACE FUNCTION everything_but(tab IN TABLE, col in COLUMNS)
  RETURN TABLE PIPELINED
  ROW POLYMORPHIC USING poly_pkg;
/

create table employee as
select 1 id, 'John' firstname, 'Smith' lastname, 'fishing' hobbies from dual;
0
Jon Heller