Comment utiliser UNION de requête d'interrogation sur n jeux d'enregistrements lorsque la portée est requise?

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

  •  20-08-2019
  •  | 
  •  

Question

Je voudrais pouvoir interroger une requête sur UNION avec un nombre inconnu de jeux d'enregistrements. Toutefois, lors d’une requête de requête, les points et les crochets ne sont pas autorisés dans les noms de jeux d’enregistrements.

Par exemple, cela échoue:

<cfquery name="allRecs" dbtype="query">
    SELECT * FROM recordset[1]
    UNION
    SELECT * FROM recordset[2]
</cfquery>

Utilisation de noms de variables dynamiques tels que " recordset1 " travail, mais cela est dans une fonction et doit être var-scoped donc je ne peux pas construire les noms de variable de manière dynamique sans produire des fuites de mémoire dans un objet persistant.

Avez-vous d'autres idées?

Était-ce utile?

La solution

Tâche difficile. Je pouvais imaginer une solution avec une boucle imbriquée basée sur GetColumnNames(), utilisant QueryAddRow() et QuerySetCell(). Ce ne sera pas le plus efficace, mais ce n’est pas vraiment lent. Cela dépend bien sûr de la taille de la tâche.

Votre " créer une fonction qui combine deux jeux d’enregistrements & "; pourrait être beaucoup plus efficace si vous le créez pour accepter, par exemple, dix arguments. Modifier le SQL à la volée:

<cfset var local = StructNew()>

<cfquery name="local.union" dbtype="query">
  SELECT * FROM argument1
  <cfloop from="2" to="#ArrayLen(arguments)#" index="local.i">
    <cfif IsQuery(arguments[local.i])>
      UNION
      SELECT * FROM argument#local.i#
    </cfif>
  </cfloop>
</cfquery>

<cfreturn local.union>

Autres conseils

Après avoir posté la question, j'ai proposé quelques solutions, mais il pourrait y en avoir une meilleure

  • Je pourrais écrire des variables nommées de manière dynamique dans la portée des arguments, puis les référencer sans leur portée dans la requête

  • Créez une fonction qui accepte 2 jeux d'enregistrements en tant qu'arguments et renvoie un jeu d'enregistrements combiné. Cela pourrait être bouclé pour ajouter progressivement un jeu d'enregistrements à la fois. Je suis sûr que cela est très inefficace par rapport à toutes les unions dans une même requête.

Après un petit moment de fouille, j'ai trouvé ceci: queryConcat sur CFLib.org. Il utilise queryaddrow / querysetcell pour concaténer deux requêtes.

J'ai ajouté une fonction rapide (sans vérification des erreurs ni validation des données, afin de ne pas l'utiliser telle quelle):

<cffunction name="concatenate">
     <cfset var result = arguments[1]>
     <cfloop from="2" to="#arraylen(arguments)#" index="i">
             <cfset result=queryconcat(result, arguments[i])>
     </cfloop>
     <cfreturn result>
 </cffunction>

En guise de test, j'ai jeté ceci ensemble:

Ce qui, en fait, vous donne fred / sammy / fred.

Ce n’est probablement pas l’implémentation la plus efficace, mais vous pouvez toujours modifier le code d’insertion / union pour le rendre plus rapide si vous le souhaitez. La plupart du temps, je souhaitais écrire le moins de code possible par moi-même. : -)

toutes les solutions ajoutées ici devraient fonctionner pour vous, mais je voudrais également mentionner que, selon le volume de données sur lequel vous travaillez et la base de données que vous utilisez, il serait peut-être préférable de chercher un moyen de le faire la base de données. Avec de très grands ensembles d’enregistrements, il peut être intéressant d’écrire les enregistrements dans une table temporaire et de les sélectionner à nouveau. Toutefois, si vous pouvez réécrire les requêtes de manière à laisser la base de données gérer cela en premier lieu, vous serez mieux.

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