web-dev-qa-db-fra.com

ORA-01008: toutes les variables ne sont pas liées. Ils sont liés

Je suis tombé sur un problème Oracle pour lequel je n'ai pas encore trouvé la cause ..___. La requête ci-dessous fonctionne dans Oracle SQL Developer, mais lors de l'exécution en .NET, elle renvoie:

ORA-01008: toutes les variables ne sont pas liées

J'ai essayé:

  • Modification du type de données Oracle pour lot_priority (Varchar2 ou int32).
  • Modification du type de données .NET pour lot_priority (string ou int).
  • Un nom de variable de liaison est utilisé deux fois dans la requête. Ce n'est pas un problème dans mon Autres requêtes qui utilisent la même variable liée dans plus d'un emplacement , Mais juste pour être sûr que j'ai essayé de faire de la seconde instance sa propre variable Avec une différente: name et le reliant séparément.
  • Plusieurs façons différentes de lier les variables (voir le code commenté; Ainsi que d’autres).
  • Déplacement de l'appel bindByName ().
  • Remplacer chaque variable liée par un littéral. Le problème est dû à deux variables distinctes (: lot_pri et: lot_priprc). Il y a eu quelques changements mineurs dont je ne me souviens plus. Le passage à des littéraux a rendu la requête efficace, mais ils ont besoin de travailler avec une liaison.

La requête et le code suivent. Les noms de variables ont été modifiés pour protéger l'innocent:

SELECT rf.myrow floworder, rf.stage, rf.prss,
rf.pin instnum, rf.prid, r_history.rt, r_history.wt
FROM
(
    SELECT sub2.myrow, sub2.stage, sub2.prss, sub2.pin, sub2.prid
    FROM (
        SELECT sub.myrow, sub.stage, sub.prss, sub.pin,
            sub.prid, MAX(sub.target_rn) OVER (ORDER BY sub.myrow) target_row
            ,sub.hflag
        FROM (
            WITH floc AS 
            (
                SELECT flow.prss, flow.seq_num
                FROM rpf@mydblink flow
                WHERE flow.parent_p = :lapp
                AND flow.prss IN (
                    SELECT r_priprc.prss
                    FROM r_priprc@mydblink r_priprc
                    WHERE priprc = :lot_priprc
                )
                AND rownum = 1
            )
            SELECT row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num) myrow,
                rpf.stage, rpf.prss, rpf.pin,
                rpf.itype, hflag,
            CASE WHEN rpf.itype = 'SpecialValue'
                THEN rpf.instruction
                ELSE rpf.parent_p
            END prid,
            CASE WHEN rpf.prss = floc.prss
                AND rpf.seq_num = floc.seq_num
                THEN row_number() OVER (ORDER BY pp.seq_num, rpf.seq_num)
            END target_rn
            FROM floc, rpf@mydblink rpf
            LEFT OUTER JOIN r_priprc@mydblink pp
                ON (pp.prss = rpf.prss)
            WHERE pp.priprc = :lot_priprc
            ORDER BY pp.seq_num, rpf.seq_num
        ) sub
    ) sub2
    WHERE sub2.myrow >= sub2.target_row
    AND sub2.hflag = 'true'
) rf
LEFT OUTER JOIN r_history@mydblink r_history
ON (r_history.lt = :lt
    AND r_history.pri = :lot_pri
    AND r_history.stage = rf.stage
    AND r_history.curp = rf.prid
)
ORDER BY myrow

public void runMyQuery(string lot_priprc, string lapp, string lt, int lot_pri) {
Dictionary<int, foo> bar = new Dictionary<int, foo>();
using(var con = new OracleConnection(connStr)) {
    con.Open();

    using(var cmd = new OracleCommand(sql.rtd_get_flow_for_lot, con)) { // Query stored in sql.resx
        try {
            cmd.BindByName = true;
            cmd.Prepare();
            cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2)).Value = lapp;
            cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2)).Value = lot_priprc;
            cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2)).Value = lt;
            // Also tried OracleDbType.Varchar2 below, and tried passing lot_pri as an integer
            cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Int32)).Value = lot_pri.ToString();
            /*********** Also tried the following, more explicit code rather than the 4 lines above: **
            OracleParameter param_lapp
                = cmd.Parameters.Add(new OracleParameter("lapp", OracleDbType.Varchar2));
            OracleParameter param_priprc
                = cmd.Parameters.Add(new OracleParameter("lot_priprc", OracleDbType.Varchar2));
            OracleParameter param_lt
                = cmd.Parameters.Add(new OracleParameter("lt", OracleDbType.Varchar2));
            OracleParameter param_lot_pri
                = cmd.Parameters.Add(new OracleParameter("lot_pri", OracleDbType.Varchar2));
            param_lapp.Value = lastProcedureStackProcedureId;
            param_priprc.Value = lotPrimaryProcedure;
            param_lt.Value = lotType;
            param_lot_pri.Value = lotPriority.ToString();
            //***************************************************************/
            var reader = cmd.ExecuteReader();
            while(reader.Read()) {
                // Get values from table (Never reached)
            }
        }
        catch(OracleException e) {
            //     ORA-01008: not all variables bound
        }
    }
}

Pourquoi Oracle prétend-il que toutes les variables ne sont pas liées?

23
Charles Burns

J'ai trouvé comment exécuter la requête sans erreur, mais j'hésite à l'appeler une "solution" sans vraiment comprendre la cause sous-jacente.

Cela ressemble plus au début de ma requête actuelle:

-- Comment
-- More comment
SELECT rf.flowrow, rf.stage, rf.process,
rf.instr instnum, rf.procedure_id, rtd_history.runtime, rtd_history.waittime
FROM
(
    -- Comment at beginning of subquery
    -- These two comment lines are the problem
    SELECT sub2.flowrow, sub2.stage, sub2.process, sub2.instr, sub2.pid
    FROM ( ...

Le deuxième groupe de commentaires ci-dessus, au début de la sous-requête, était le problème. Une fois supprimée, la requête s'exécute. Les autres commentaires sont corrects . Il ne s’agit pas d’une ligne brisée ou manquante, ce qui entraîne le commentaire de la ligne suivante, car celle-ci est un SELECT. Une sélection manquante produirait une erreur différente de "toutes les variables ne sont pas liées".

J'ai demandé autour de moi et ai trouvé un collègue qui a rencontré ce problème - des commentaires à l'origine des échecs de requête - plusieurs fois ... Quelqu'un sait-il en quoi cela peut être la cause? Je crois comprendre que la première chose qu’un SGBD ferait avec des commentaires est de voir s’ils contiennent des astuces, sinon, supprimez-les lors de l’analyse. Comment un commentaire ordinaire ne contenant aucun caractère inhabituel (juste des lettres et un point) peut-il causer une erreur? Bizarre.

13
Charles Burns

Je sais que c’est une vieille question, mais elle n’a pas été correctement adressée. C’est pourquoi je réponds à d’autres qui risquent de se heurter à ce problème.

Par défaut, ODP.net d’Oracle lie les variables par position et traite chaque position en tant que nouvelle variable. 

Le traitement de chaque copie comme une variable différente et la définition de sa valeur plusieurs fois constituent une solution de contournement et une douleur, comme mentionné par furman87, et peuvent conduire à des erreurs si vous essayez de réécrire la requête et de déplacer des éléments.

La méthode correcte consiste à définir la propriété BindByName de OracleCommand sur true comme suit:

var cmd = new OracleCommand(cmdtxt, conn);
cmd.BindByName = true;

Vous pouvez également créer une nouvelle classe pour encapsuler OracleCommand en définissant BindByName sur true lors de l'instanciation. Vous n'avez donc pas à définir la valeur à chaque fois. Ceci est discuté dans this post

8
Vijay Jagdale

Vous avez deux références à la variable de liaison: lot_priprc - alors qu'elle devrait vous obliger à définir la valeur de la variable une seule fois et à la lier aux deux endroits, j'ai eu des problèmes où cela ne fonctionnait pas et que je devais traiter chaque copie en tant que variable différente. Une douleur, mais ça a fonctionné.

7
furman87

Je suis venu chercher de l'aide, car la même erreur s'est produite lors de l'exécution d'une déclaration ci-dessous lors du parcours Udemy: 

INSERT INTO departments (department_id, department_name)
                  values( &dpet_id, '&dname');  

J'avais déjà pu exécuter des instructions avec des variables de substitution. Le commentaire de Charles Burns sur la possibilité que le serveur atteigne un certain seuil tout en recréant les variables m'a incité à me déconnecter et à redémarrer le développeur SQL. La déclaration a fonctionné correctement après la connexion.

Je pensais que je partagerais avec quiconque s'aventurerait ici avec un problème de portée limitée comme le mien.

1
Qudsia

La solution dans ma situation était une réponse similaire à Charles Burns; et le problème était lié aux commentaires de code SQL. 

Je construisais (ou mettais plutôt à jour) un rapport SSRS déjà opérationnel avec la source de données Oracle. J'ai ajouté quelques paramètres supplémentaires au rapport, je l'ai testé dans Visual Studio. Cela fonctionne très bien. Je l'ai donc déployé sur le serveur de rapports, puis lorsque le rapport est exécuté, le message d'erreur s'affiche:

"ORA-01008: toutes les variables ne sont pas liées"

J'ai essayé pas mal de choses différentes (fichier TNSNames.ora installé sur le serveur, commentaires de ligne supprimés, validation du mappage de requête de jeu de données). En fin de compte, je devais supprimer un bloc de commentaires directement après le WHERE keyword. Le message d'erreur a été résolu après déplacer le bloc de commentaires après le WHERE CLAUSE conditions. J'ai aussi d'autres commentaires dans le code. C'était juste après le mot-clé WHERE à l'origine de l'erreur. 

SQL avec l'erreur: "ORA-01008: toutes les variables ne sont pas liées" ...

WHERE
/*
    OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE=100
    AND OHH.MASTER_ORDER_NBR IS NULL
*/

    OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE IN (:paramCompany)
    AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse) 
    AND OHH.MASTER_ORDER_NBR IS NULL
    AND LOAD.CLASS_CODE IN (:paramClassCode) 
    AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto) 

SQL s'exécute avec succès sur le serveur de rapports ...

WHERE
    OHH.SHIP_DATE BETWEEN :paramStartDate AND :paramEndDate
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE IN (:paramCompany)
    AND LOAD.DEPART_FROM_WHSE_CODE IN (:paramWarehouse) 
    AND OHH.MASTER_ORDER_NBR IS NULL
    AND LOAD.CLASS_CODE IN (:paramClassCode) 
    AND CUST.CUST_CODE || '-' || CUST.CUST_SHIPTO_CODE IN (:paramShipto)   
/*
    OHH.SHIP_DATE BETWEEN TO_DATE('10/1/2018', 'MM/DD/YYYY') AND TO_DATE('10/31/2018', 'MM/DD/YYYY')
    AND OHH.STATUS_CODE<>'DL'
    AND OHH.BILL_COMP_CODE=100
    AND OHH.MASTER_ORDER_NBR IS NULL
*/

Voici à quoi ressemble l'écran de mappage des paramètres du jeu de données. 

 enter image description here

1

C’est un bogue dans Managed ODP.net - 'Bug 21113901: MANAGED ODP.NET RELEVER ORA-1008 UTILISANT UN SEUL COTÉ CONST + BIND VAR DANS SELECT' corrigé dans le correctif 23530387 remplacé par le correctif 24591642

1
durzy

Sur le problème de commentaire de Charles: pour aggraver les choses, laissez

:p1 = 'TRIALDEV'

via un paramètre de commande, puis exécutez

select T.table_name as NAME, COALESCE(C.comments, '===') as DESCRIPTION
from all_all_tables T
Inner Join all_tab_comments C on T.owner = C.owner and T.table_name = C.table_name
where Upper(T.owner)=:p1
order by T.table_name

558 line(s) affected. Processing time: 00:00:00.6535711

et lors du changement de la chaîne littérale de === en ---

select T.table_name as NAME, COALESCE(C.comments, '---') as DESCRIPTION
[...from...same-as-above...]

ORA-01008: not all variables bound

Les deux instructions s'exécutent correctement dans SQL Developer. Le code abrégé:

            Using con = New OracleConnection(cs)
                con.Open()
                Using cmd = con.CreateCommand()
                    cmd.CommandText = cmdText
                    cmd.Parameters.Add(pn, OracleDbType.NVarchar2, 250).Value = p
                    Dim tbl = New DataTable
                    Dim da = New OracleDataAdapter(cmd)
                    da.Fill(tbl)
                    Return tbl
                End Using
            End Using

utilisant Oracle.ManagedDataAccess.dll version 4.121.2.0 avec les paramètres par défaut dans VS2015 sur la plate-forme .Net 4.61.

Donc, quelque part dans la chaîne d’appel, il se peut qu’un analyseur syntaxique cherche un peu trop agressivement les commentaires d’une ligne commençant par - dans le commandText. Mais même si cela devait être vrai, le message d'erreur "toutes les variables ne sont pas liées" est au moins trompeur.

1
Zartag

Je rencontrais un problème similaire dans une application héritée, mais de "-" était un paramètre de chaîne.

Ex.:

 Dim cmd As New OracleCommand ("INSERT INTO USER (nom, adresse, photo) VALEURS ('User1', '-',: photo)", oracleConnection) 
 Dim fs As IO.FileStream = New IO .FileStream ("c:\img.jpg", IO.FileMode.Open) 
 Dim br Comme New IO.BinaryReader (fs) 
 Cmd.Parameters.Add (New OracleParameter ("photo", OracleDbType.Blob )). Valeur = br.ReadBytes (fs.Length) 
 Cmd.ExecuteNonQuery () 'lève ici ORA-01008 

Changer la valeur du paramètre d'adresse '-' en '00' ou autre chose fonctionne.

0
Roger