2009-08-26 6 views
0

J'utilise ColdFusion for pour un projet et j'ai une requête écrite qui peut être plus rapide en utilisant une procédure stockée, mais je ne suis pas une personne T-SQL, donc Je ne suis pas sûr de savoir comment le faire pour comparer.Mise à jour de la table basée sur Sélectionner une requête dans la procédure stockée/ColdFusion

Je lance une requête initiale qui sélectionne un nombre de champs d'une table basée sur une requête cfqu dynamiquement construite. Je pense que je sais comment convertir cette requête dans la procédure stockée SQL Server.

Cependant, directement après cela, je prends tous les ID de clé primaire de cette requête et exécute une autre requête sur une table distincte qui «verrouille» les enregistrements avec ces ID. Le verrou est un champ de bits (un drapeau) dans la seconde table qui indique au système que cet enregistrement est "extrait". J'ai enveloppé les deux requêtes dans un cftransaction afin qu'ils s'exécutent en tant qu'unité.

code Vue d'ensemble:

<cftransaction> 
    <cfquery name="selectQuery"> 
     SELECT id, field2, field3 
     FROM table1 
     WHERE (bunch of conditions here) 
    </cfquery> 

    <cfquery name="updateQuery"> 
     UPDATE table2 
     SET lockField = 1 
     WHERE table2.id IN (#ValueList(selectQuery.id#) 
    </cfquery> 
</cftransaction> 

Je reviens alors à selectQuery mon application resultset qui l'utilise pour produire des données. Comment pourrais-je accomplir la même chose dans une seule procédure stockée SQL Server 2008 que je pourrais appeler en utilisant cfstoredproc? Encore une fois, je pense que le chemin CF natif (avec cfquery) n'est pas aussi efficace qu'une procédure stockée puisque je dois ramener le résultat à CF, puis réappeler une autre requête à la DB. Une procédure stockée unique fait tout dans la base de données et renvoie ensuite le jeu de résultats de requête d'origine à utiliser.

Des idées?

Répondre

0

Vous pouvez faire votre mise à jour dans une requête en faisant de votre première requête une sous-requête, puis en utilisant une instruction séparée pour renvoyer vos résultats. Tout cela pourrait être une seule procédure stockée:

CREATE PROCEDURE myUpdate 
     @Variable [datatype], etc... 
    AS 
    BEGIN 
    UPDATE table2 
    SET lockField = 1 
    WHERE table2.id IN (
     SELECT id 
     FROM table1 
     WHERE (bunch of conditions here) 
    ) 
    SELECT id, field2, field3 
    FROM table1 
    WHERE (bunch of conditions here) 
    END 

Vous devrez probablement passer certains paramètres, mais c'est la structure de base d'une procédure stockée. Ensuite, vous pouvez l'appeler de ColdFusion comme ceci:

<cfstoredproc procedure="myUpdate"> 
    <cfprocparam type="[CF SQL Type]" value="[CF Variable]"> 
    etc... 
    <cfprocresult name="selectQuery" resultSet="1"> 
</cfstoredproc> 

Vous pouvez utiliser ces résultats de la requête comme vous les utilisiez avant.

+0

Ok, j'ai besoin d'un test de santé pour cette réponse. Les données de table1 sont en flux constant ... c'est essentiellement une file d'attente. Parce que c'est dans un seul storedproc, il fonctionne essentiellement comme une seule transaction, n'est-ce pas? Ce qui signifie, puisque je cours deux fois le SELECT sur la table 1, je dois garantir que je reçois les mêmes résultats les deux fois. Comme de nombreux utilisateurs utiliseront régulièrement cette fonction, je dois m'assurer que le "verrouillage" fonctionne correctement. –

+0

Non, ce n'est pas une transaction unique. Si vous avez besoin des données pour la sortie avant d'exécuter la mise à jour, vous devrez le faire différemment. Je n'ai pas compris toute la question du verrouillage dans votre question. –

1

Votre problème est "tas de conditions ici". Ces conditions sont-elles toujours statiques? Alors est-ce TOUJOURS: (FOO = @x ET BAR = @y)? Ou est-ce conditionnel où parfois FOO n'existe pas du tout comme une condition?

Si FOO n'est pas toujours présent, vous avez un problème avec le proc mémorisé. T-SQL ne peut pas faire de construction de requête dynamique, en fait même en lui permettant de nier le point de la proc, qui est de compiler et de pré-optimiser le SQL. Vous pouvez le faire bien sûr, mais vous finissez par avoir juste à construire une chaîne SQL à l'intérieur du corps proc et ensuite l'exécuter à la fin. Il vaut mieux utiliser CFQuery avec cfqueryparams. En fait avez-vous envisagé de le faire à la place?

<cfquery name="updateQuery"> 
     UPDATE table2 
     SET lockField = 1 
     WHERE table2.id IN (SELECT id 
          FROM table1 
          WHERE (bunch of conditions here)) 
    </cfquery> 
+0

Le problème est que je dois retourner le jeu de résultats de l'instruction select de table1, et pas seulement mettre à jour table2. –

1

Vous pouvez ajouter une clause de sortie à l'instruction UPDATE pour capturer les id des enregistrements mis à jour et de les insérer dans une table variable de table/temp. Puis REJOINDRE à table1 pour renvoyer le jeu de résultats.

DECLARE @UpdatedRecords TABLE (ID INT) 

UPDATE t2 
SET  t2.lockField = 1 
OUTPUT Inserted.ID INTO @UpdatedRecords (ID) 
FROM table2 t2 INNER JOIN table1 t1 ON t2.id = t1.id 
WHERE (bunch of conditions for table1 here) 

SELECT t1.id, t1.field2, t1.field3 
FROM table1 t1 INNER JOIN @UpdatedRecords u ON t1.id = u.id 

Gardez à l'esprit que si table1 est en pleine mutation constante, les autres valeurs (« field2 » et « Field3 ») ne sont pas garantis d'être ce qu'ils étaient quand UPDATE a eu lieu.Mais je pense que votre méthode actuelle est également sensible à ce problème.

0

Pas besoin de SPROC.

UPDATE table2 
SET table2.lockField = 1 
FROM table1 
WHERE table1.id = table2.id 
    AND table1.field2 = <cfqueryparam ....> 
    AND table1.field3 = <cfqueryparam ....> 
+0

Oups. Je me suis rendu compte que c'était une question majeure de nécromancie. : - / – Shawn

Questions connexes