Comment interroger plusieurs tables SQL pour une paire clé-valeur spécifique?

StackOverflow https://stackoverflow.com/questions/104230

  •  01-07-2019
  •  | 
  •  

Question

Situation: une application PHP avec plusieurs modules installables crée une nouvelle table dans la base de données, dans le style de mod_A, mod_B, mod_C, etc. Chacune a la colonne section_id.

Maintenant, je recherche toutes les entrées pour une section_id spécifique et j'espère qu'il existe un autre moyen que "Sélectionner * dans mod_a, mod_b, mod_c ... mod_xyzzy où section_id = value" ... ou même pire. , en utilisant une requête distincte pour chaque module.

Était-ce utile?

La solution

Si les tables changent avec le temps, vous pouvez intégrer du code en ligne à votre solution dans un SP (pseudo-code - vous devrez le renseigner):

SET @sql = ''

DECLARE CURSOR FOR
SELECT t.[name] AS TABLE_NAME
FROM sys.tables t
WHERE t.[name] LIKE 'SOME_PATTERN_TO_IDENTIFY_THE_TABLES'

- ou ce

DECLARE CURSOR FOR
SELECT t.[name] AS TABLE_NAME
FROM TABLE_OF_TABLES_TO_SEACRH t

START LOOP

IF @sql <> '' SET @sql = @sql + 'UNION ALL '
SET @sql = 'SELECT * FROM [' + @TABLE_NAME + '] WHERE section_id=value '

END LOOP

EXEC(@sql)

J'ai utilisé cette technique de temps en temps, quand il n'y a pas de moyen évident de la rendre pérenne sans SQL dynamique.

Remarque: dans votre boucle, vous pouvez utiliser l'astuce de propagation COALESCE / NULL et laisser la chaîne NULL avant la boucle, mais ce n'est pas aussi clair si vous ne connaissez pas l'idiome:

SET @sql = COALESCE(@sql + ' UNION ALL ', '')
    + 'SELECT * FROM [' + @TABLE_NAME + '] WHERE section_id=value '

Autres conseils

Qu'en est-il?

SELECT * FROM mod_a WHERE section_id=value
UNION ALL
SELECT * FROM mod_b WHERE section_id=value
UNION ALL
SELECT * FROM mod_c WHERE section_id=value

J'ai deux suggestions.

  1. Peut-être avez-vous besoin de consolider toutes vos tables. Si elles contiennent toutes la même structure, pourquoi ne pas en créer un " maître " table de module, qui ajoute simplement une nouvelle colonne identifiant le module ("A", "B", "C", ...)

    Si vos tables de modules sont généralement identiques, mais que vous avez quelques colonnes différentes, vous pourrez peut-être consolider toutes les informations communes dans une seule table et conserver des tables plus petites spécifiques à un module avec ces différences. Ensuite, il vous suffira de faire une jointure.

    Cette suggestion suppose que votre requête sur la colonne section_id que vous avez mentionnée est extrêmement critique pour une recherche rapide. Avec une requête, vous obtenez toutes les informations communes, et avec une seconde, vous obtenez des informations spécifiques si vous en avez besoin. (Et vous pourriez ne pas le faire - par exemple, si vous tentiez de valider l’existence de la section, le trouver dans le tableau commun suffirait)

  2. Vous pouvez également ajouter une autre table qui mappe les identificateurs de section aux modules dans lesquels ils se trouvent.

    section_id | module
    -----------+-------
          1    |  A
          2    |  B
          3    |  A
         ...   | ...
    

    Cela signifie cependant que vous devez exécuter deux requêtes, une contre cette table de mappage et une autre contre la table de module pour extraire toutes les données utiles.

    Vous pouvez étendre ce tableau avec d'autres colonnes et index sur ces colonnes si vous devez rechercher d'autres colonnes communes à tous les modules.

    Cette méthode a le désavantage définitif de dupliquer les données.

Peut-être que quelques informations supplémentaires pourraient vous aider, mais il semble que vous ayez déjà la solution. Vous devrez choisir parmi toutes les tables avec un identifiant de section. Vous pouvez utiliser des jointures au lieu d'une liste de tables, en rejoignant section_id. Par exemple

select a.some_field, b.some_field.... 
from mod_a a
inner join mod_b b on a.section_id = b.section_id
...
where a.section_id = <parameter>

Vous pouvez également créer un package sous forme de vue. Notez également la liste des champs au lieu de *, ce que je vous recommanderais si vous aviez l'intention d'utiliser réellement *.

Eh bien, il n’existe que de nombreuses façons de regrouper des informations provenant de plusieurs tables. Vous pouvez vous joindre, comme vous l'avez mentionné dans votre exemple, ou vous pouvez exécuter plusieurs requêtes et les unir comme dans la réponse de Borjab. Je ne sais pas si une idée de créer une table qui intersecte toutes les tables de modules vous serait utile, mais si section_id était sur une table comme celle-ci, vous pourriez tout obtenir à partir d'une seule requête. Sinon, j'applaudis votre paresse, mais j'ai peur de dire, je ne vois pas comment rendre ce travail plus rapide:)

J'allais suggérer la même chose que Borjab. Le seul problème avec cela est que vous devrez mettre à jour toutes ces requêtes si vous ajoutez une autre table. La seule autre option que je vois est une procédure stockée.

J'ai pensé à une autre option ici, ou du moins à un moyen plus simple de présenter cela. Vous pouvez également utiliser une vue sur ces tables multiples pour les faire apparaître comme une seule. Votre requête sera alors plus claire, plus facile à comprendre et vous n’auriez pas à réécrire une requête longue union lorsque vous souhaitez effectuer d’autres requêtes sur ces tables. plusieurs tables.

SELECT * FROM (
    SELECT * FROM table1
    UNION ALL
    SELECT * FROM table2
    UNION ALL
    SELECT * FROM table3
) subQry
WHERE field=value

Une des options de la base de données serait de créer une vue de l’UNION ALL des différentes tables. Lorsque vous ajoutez une table, vous devez l’ajouter à la vue, mais sinon, elle ressemble à une seule table.

CREATE VIEW modules AS (
    SELECT * FROM mod_A
    UNION ALL 
    SELECT * FROM mod_B
    UNION ALL 
    SELECT * FROM mod_C
);

select * from modules where section_id=value;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top