7
votes

SQL: Recherchez une liste des colonnes avec une valeur donnée (dans une rangée)

J'ai une table avec plusieurs colonnes . Existe-t-il un moyen de faire une requête qui répond à la question suivante: "Pour un identifiant particulier (la clé primaire), quel champ (s) dans cette ligne a une valeur de 10"?

EDIT:

Clarification: la table est configurée correctement. L'interrogation que je fais est une interrogation manuelle lorsque je suivez quelques données incorrectes. La table a été optimisée pour être la plus rapide pour les requêtes automatisées qui représentent les vastes majorités des requêtes exécutées. (Et avec plus de 95 millions de lignes, chaque optimisation est importante)

Je me rends compte que ma question demande à faire quelque chose que SQL n'était pas destiné à faire. J'espère juste qu'il y a du truc pour obtenir ce que je veux.

Modifier pour la postérité:

Dans notre système, nous avons de nombreux comptes d'utilisateurs différents. Un compte est celui que nous utilisons pour toutes les requêtes en lecture seule (c'est celui que j'utilise la plupart du temps). Il ne possède pas les tables en question, alors quand j'adapais la réponse à ma situation, je devais faire le changement suivant:

user_tab_columns devait devenir all_tab_columns et je devais ajouter propriétaire = '[propriétaire]' à la requête.


0 commentaires

3 Réponses :


1
votes

On dirait que votre base de données n'est pas correctement normalisée. Cela dit, vous pouvez probablement utiliser la commande impucheuse dans une sous-requête pour faire ce que vous essayez de faire.


2 commentaires

Souhaitez-vous plus de détails sur l'impulsion? Plus précisément, intact l'impuche à Oracle?


@David Oneill: impulsion (et pivot est uniquement pris en charge par Oracle 11G +. N'importe quoi plus tôt que cela ne nécessite d'utiliser ou Decode Décodements - Vérifiez les étiquettes SQL, pivot et / ou classement à ce sujet.



3
votes

Ce n'est pas une pièce normale de fonctionnalité de base de données. Cependant, vous n'êtes pas la première personne qui a demandé cela, ou quelque chose comme ça.

La solution nécessite deux choses. Le premier est le dictionnaire de données; La base de données Oracle ne supporte pas la réflexion, mais elle vient avec un ensemble de vues qui nous donnent des métadonnées sur nos objets de base de données. Dans ce cas, nous avons besoin user_tab_columns code>, qui nous donnera les colonnes pour une table donnée. La deuxième chose est dynamique SQL; C'est la possibilité d'assembler une requête SQL au moment de l'exécution, puis de l'exécuter. Il y a quelques façons de faire cela, mais les curseurs REF sont généralement suffisants. P>

Le code suivant est une preuve de concept. Il faut quatre paramètres: p>

  1. Le nom de la table que vous souhaitez rechercher li>
  2. Le nom de la clé primaire de cette table Colonne li>
  3. la valeur principale de la clé que vous voulez restreindre par li>
  4. la valeur que vous souhaitez rechercher. li> ol>

    Il est rude'n'rédéty afin que vous puissiez le modifier pour ranger la sortie ou pour rendre le programme plus flexible. P>

    SQL> set serveroutput on size unlimited
    SQL> exec search_cols('T23', 'ID', 111, 10)
    T23::10 found in ,COL_B,COL_C,
    
    PL/SQL procedure successfully completed.
    
    SQL> exec search_cols('T23', 'ID', 222, 10)
    T23::10 found in COL_A,,,
    
    PL/SQL procedure successfully completed.
    
    SQL>
    


1 commentaires

Oui, c'était le genre de chose que je savais devait être dehors. Merci!



1
votes

Ma solution utiliserait des tables de dictionnaire (user_tab_columns) pour aller chercher de manière dynamique le nom de toutes les colonnes numériques de votre table et Dynamic SQL, car ici, je ne vois pas comment on pourrait l'éviter.

DECLARE
   CURSOR cur_columns IS
          select COLUMN_NAME from USER_TAB_COLUMNS 
          where TABLE_NAME='<MY_TABLE>' and DATA_TYPE='NUMBER';
   query_text VARCHAR2(1000);
   result_value NUMBER;
BEGIN
   -- Iterate through each NUMBER column of the table
   FOR rec_col IN cur_columns LOOP

       -- In my line of primary key <MY_ID>, check if the current column has
       --  the wanted value.
       query_text := 
         'SELECT count(1) FROM <MY_TABLE> WHERE <TABLE_ID> = <MY_ID> AND ' 
         || rec_col.COLUMN_NAME || ' = <MY_VALUE>'; -- < the "magic" is here

       EXECUTE IMMEDIATE query_text INTO result_value; 

       IF result_value > 0 THEN
          DBMS_OUTPUT.PUT_LINE('Got a match for column ' || 
                               rec_col.COLUMN_NAME || '.');
       END IF;

   END LOOP;
END;


1 commentaires

Oui, c'était le genre de chose que je savais devait être dehors. Merci!