ORA-06502: PL/SQL: 数字或值错误: NULL 索引表键值

Posted

技术标签:

【中文标题】ORA-06502: PL/SQL: 数字或值错误: NULL 索引表键值【英文标题】:ORA-06502: PL/SQL: numeric or value error: NULL index table key value 【发布时间】:2019-07-22 09:53:54 【问题描述】:

我正在尝试将临时表中的数据分派到目标表中。 代码已经由第三方开发者编写,但在他们离开之前从未测试过。

我设法纠正了其他错误,现在第一行给了我以下错误:

ORA-06502:PL/SQL:数字或值错误:NULL 索引表键值。

 DECLARE
  -- in-memory cache table type
  TYPE CODE_ID_MAP IS TABLE OF NUMBER(20) INDEX BY VARCHAR2(1200);

  -- in-memory chache tables
  magasins_map CODE_ID_MAP;
  type_canal_map CODE_ID_MAP;
  partenaires_map CODE_ID_MAP;
  types_adresses_map CODE_ID_MAP;
  types_magasins_map CODE_ID_MAP;
  statut_donnees_partenaire_map CODE_ID_MAP;

  -- cursor on input data
  CURSOR imp_cur IS
    SELECT
      extern.*,
      c.id     AS idcarteu, -- correspond a "extern.numero_carte"

      m0.id    AS old_membres_id0,
      m0.idrxp AS idrxp0,
      c0.id    AS idcarteu0,

      m1.id    AS old_membres_id1,
      m1.idrxp AS idrxp1,
      c1.id    AS idcarteu1,

      m2.id    AS old_membres_id2,
      m2.idrxp AS idrxp2,
      c2.id    AS idcarteu2

    FROM batch_rxp2bmc extern

    LEFT JOIN donnees_carteu c  ON extern.numero_carte = c.numero_carte

    LEFT JOIN membres m0        ON extern.membre_idrxp0 = m0.idrxp
    LEFT JOIN donnees_carteu c0 ON m0.donnees_carteu_id = c0.id

    LEFT JOIN membres m1        ON extern.membre_idrxp1 = m1.idrxp
    LEFT JOIN donnees_carteu c1 ON m1.donnees_carteu_id = c1.id

    LEFT JOIN membres m2        ON extern.membre_idrxp2 = m2.idrxp
    LEFT JOIN donnees_carteu c2 ON m2.donnees_carteu_id = c2.id;

  TYPE IMP_TBL_TYPE IS TABLE OF imp_cur%ROWTYPE;
  imp_row imp_cur%ROWTYPE;
  imp_tbl IMP_TBL_TYPE;
  imp_cur_max PLS_INTEGER := 5000;

  PROCEDURE log (level VARCHAR2, lino NUMBER, msg VARCHAR2) IS BEGIN
    dbms_output.put_line('[' || level || '][#' || lino || '] ' || msg);
  END log;


  PROCEDURE update_membre (
    lino NUMBER,                    -- numero de ligne
    m imp_cur%ROWTYPE,              -- donnees deversees
    old_membres_id membres.id%TYPE, -- sujet de la mise-a-jour
    old_carteu_id donnees_carteu.id%TYPE -- carte-u du sujet de la mise-a-jour
  )
  IS
    new_carteu_id donnees_carteu.id%TYPE;
  BEGIN
    log('INFO', lino, 'mise-a-jour du membre ' || m.membre_identifiant);

    -- rendre l'id variable -- imp_row "m" est en lecture seule
    new_carteu_id := m.idcarteu;

    -- insertion de la carte si elle n'existe pas
    IF new_carteu_id IS NULL THEN
      new_carteu_id := seq_donnees_carteu_id.nextval;
      INSERT INTO donnees_carteu (id, numero_carte) VALUES (new_carteu_id, m.numero_carte);
    END IF;

    -- alerte si le client change de carte-u car l'ancienne
    -- n'est pas supprime en cascade et devient orphelin.
    IF new_carteu_id != old_carteu_id THEN
      log('WARN', lino,
        m.membre_identifiant || ' change de carte-u : ' ||
        'la ' || new_carteu_id || ' remplace la ' || old_carteu_id || ' devenant orphelin'
      );
    END IF;

    -- mise-a-jour du membre
    UPDATE membres SET
      idrxp = m.membre_idrxp0, -- on ecrase tjrs l'id historique
      email = m.membre_email,
      identifiant = m.membre_identifiant,
      civilite = m.membre_civilite,
      nom = m.membre_nom,
      prenom = m.membre_prenom,
      naissancedate = m.membre_naissance,
      profession = m.membre_profession,
      telfixe = m.membre_tel_fixe,
      telmobile = m.membre_tel_mobile,
      situationfamiliale = m.membre_situ_fam,
      carteutypeporteur = m.membre_type_porteur,
      carteu_porteur_principal = m.membre_porteur_principal,
      donnees_carteu_id = new_carteu_id
    WHERE id = old_membres_id;

    -- mise-a-jour/insertion de l'adresse de domicile
    MERGE INTO donnees_adresses trg
      USING (
        SELECT
          old_membres_id AS membres_id,
          types_adresses_map(m.adresse_type) AS types_adresses_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.types_adresses_id = src.types_adresses_id)
    WHEN MATCHED THEN
      UPDATE SET
        adresse = m.adresse_street,
        complement_adresse = m.adresse_complement,
        code_postal = m.adresse_code_postal,
        ville = m.adresse_ville,
        pays = m.adresse_pays
    WHEN NOT MATCHED THEN
      INSERT (
        membres_id,
        types_adresses_id,
        adresse,
        complement_adresse,
        code_postal,
        ville,
        pays
      )
      VALUES (
        old_membres_id,
        types_adresses_map(m.adresse_type),
        m.adresse_street,
        m.adresse_complement,
        m.adresse_code_postal,
        m.adresse_ville,
        m.adresse_pays
      );

    -- mise-a-jour/insertion des souscriptions sms, email, courrier
    MERGE INTO donnees_communication trg
      USING (
        SELECT
          old_membres_id AS membres_id,
          type_canal_map(m.optin_sms_canal) AS canal_communication_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.canal_communication_id = src.canal_communication_id)
    WHEN MATCHED THEN
      UPDATE SET
        accepte_canal = m.optin_sms,
        date_derniere_maj = m.optin_sms_date,
        source_maj = m.optin_sms_source
      WHERE accepte_canal != m.optin_sms -- mise-a-jour si ca change qqc
    WHEN NOT MATCHED THEN
      INSERT (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      )
      VALUES (
        old_membres_id,
        m.optin_sms,
        m.optin_sms_date,
        m.optin_sms_source,
        type_canal_map(m.optin_sms_canal)
      );

    MERGE INTO donnees_communication trg
      USING (
        SELECT
          old_membres_id AS membres_id,
          type_canal_map(m.optin_email_canal) AS canal_communication_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.canal_communication_id = src.canal_communication_id)
    WHEN MATCHED THEN
      UPDATE SET
        accepte_canal = m.optin_email,
        date_derniere_maj = m.optin_email_date,
        source_maj = m.optin_email_source
      WHERE accepte_canal != m.optin_email -- mise-a-jour si ca change qqc
    WHEN NOT MATCHED THEN
      INSERT (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      )
      VALUES (
        old_membres_id,
        m.optin_email,
        m.optin_email_date,
        m.optin_email_source,
        type_canal_map(m.optin_email_canal)
      );

    MERGE INTO donnees_communication trg
      USING (
        SELECT
          old_membres_id AS membres_id,
          type_canal_map(m.optin_courrier_canal) AS canal_communication_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.canal_communication_id = src.canal_communication_id)
    WHEN MATCHED THEN
      UPDATE SET
        accepte_canal = m.optin_courrier,
        date_derniere_maj = m.optin_courrier_date,
        source_maj = m.optin_courrier_source
      WHERE accepte_canal != m.optin_courrier -- mise-a-jour si ca change qqc
    WHEN NOT MATCHED THEN
      INSERT (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      )
      VALUES (
        old_membres_id,
        m.optin_courrier,
        m.optin_courrier_date,
        m.optin_courrier_source,
        type_canal_map(m.optin_courrier_canal)
      );

    -- remplacement des enfants (nous sommes pas en mesure de faire le lien entre
    -- des enfant deja en base et ceux qui sont deverses)
    DELETE membre_enfants WHERE membre_id = old_membres_id;
    INSERT ALL
      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_1_prenom, m.enfant_1_sexe, m.enfant_1_naissance)

      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_2_prenom, m.enfant_2_sexe, m.enfant_2_naissance)

      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_3_prenom, m.enfant_3_sexe, m.enfant_3_naissance)

      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_4_prenom, m.enfant_4_sexe, m.enfant_4_naissance)

      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_5_prenom, m.enfant_5_sexe, m.enfant_5_naissance)

      INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (old_membres_id, m.enfant_6_prenom, m.enfant_6_sexe, m.enfant_6_naissance)
    SELECT * FROM dual;

    -- mise-a-jour/insertion des magasins favorites
    MERGE INTO membres_types_magasins trg
      USING (
      SELECT
        old_membres_id AS membres_id,
        magasins_map(m.fav_magasinsu) AS magasins_id,
        types_magasins_map(m.fav_magasinsu_type) AS types_magasins_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.types_magasins_id = src.types_magasins_id)
    WHEN MATCHED THEN
      UPDATE SET
        magasins_id = src.magasins_id
      WHERE magasins_id != src.magasins_id
    WHEN NOT MATCHED THEN
      INSERT (membres_id, magasins_id, types_magasins_id)
      VALUES (src.membres_id, src.magasins_id, src.types_magasins_id);

    MERGE INTO membres_types_magasins trg
      USING (
        SELECT
        old_membres_id AS membres_id,
        magasins_map(m.fav_mobileapp) AS magasins_id,
        types_magasins_map(m.fav_mobileapp_type) AS types_magasins_id
        FROM dual
      ) src
      ON (trg.membres_id = src.membres_id AND trg.types_magasins_id = src.types_magasins_id)
    WHEN MATCHED THEN
      UPDATE SET
        magasins_id = src.magasins_id
      WHERE magasins_id != src.magasins_id
    WHEN NOT MATCHED THEN
      INSERT (membres_id, magasins_id, types_magasins_id)
      VALUES (src.membres_id, src.magasins_id, src.types_magasins_id);

    -- suppression du consentement s'il n'est pas renseigne
    IF m.consentement_date IS NULL THEN
      DELETE membre_consentement WHERE id_membre = old_membres_id;

    -- creation du consentement s'il n'existe pas encore
    ELSE
      MERGE INTO membre_consentement trg
        USING (
        SELECT
          old_membres_id AS id_membre,
          m.consentement_date AS date_consentement,
          partenaires_map(m.consentement_partenaire) AS id_source_consentement
        FROM dual
        ) src
        ON (trg.id_membre = src.id_membre)
      WHEN NOT MATCHED THEN
        INSERT (id_membre, date_consentement, id_source_consentement)
        VALUES (src.id_membre, src.date_consentement, src.id_source_consentement);
    END IF;

    -- point de vigilence : munissez-vous d'un schema de la BMC
    --   la relation entre MEMBRES et DONNEES_PARTENAIRE et de cardinalite
    --   one-to-many et non many-to-many comme le sugere le tableau intermediare
    --   MEMBRES_DONNEES_PARTENAIRE. une adhesion membre-service (representee
    --   par DONNEES_PARTENAIRE) ne peut pas etre partage entre plusieurs membres.
    --   c'est une erreur dans la conception de la bdd.

    DECLARE
      donnees_partenaire_id donnees_partenaire.id%TYPE;
    BEGIN
      SELECT dp.id INTO donnees_partenaire_id FROM donnees_partenaire dp
      INNER JOIN membres_donnees_partenaire mdp
      ON mdp.donnees_partenaire_id = dp.id
      WHERE mdp.membres_id = old_membres_id
      AND dp.partenaires_id = partenaires_map(m.adhesion_magasinsu_partenaire);

      UPDATE donnees_partenaire dp
      SET statut_donnees_partenaire_id = statut_donnees_partenaire_map(m.adhesion_magasinsu_statut)
      WHERE id = donnees_partenaire_id;

    EXCEPTION 
      WHEN NO_DATA_FOUND THEN
        log('ERROR', lino, m.membre_identifiant || ' n''est pas associe a magasins-u');
    END;

    DECLARE
      donnees_partenaire_id donnees_partenaire.id%TYPE;
    BEGIN
      SELECT dp.id INTO donnees_partenaire_id FROM donnees_partenaire dp
      INNER JOIN membres_donnees_partenaire mdp
      ON mdp.donnees_partenaire_id = dp.id
      WHERE mdp.membres_id = old_membres_id
      AND dp.partenaires_id = partenaires_map(m.adhesion_mobileapp_partenaire);

      UPDATE donnees_partenaire dp
      SET statut_donnees_partenaire_id = statut_donnees_partenaire_map(m.adhesion_mobileapp_statut)
      WHERE id = donnees_partenaire_id;

    EXCEPTION 
      WHEN NO_DATA_FOUND THEN
        donnees_partenaire_id := seq_donnees_part_id.nextval;

        INSERT INTO donnees_partenaire (
          id,
          statut_donnees_partenaire_id,
          partenaires_id
        ) VALUES (
          donnees_partenaire_id,
          statut_donnees_partenaire_map(m.adhesion_magasinsu_statut),
          partenaires_map(m.adhesion_magasinsu_partenaire)
        );

        INSERT INTO membres_donnees_partenaire (
          membres_id,
          donnees_partenaire_id
        ) VALUES (
          old_membres_id,
          donnees_partenaire_id
        );
    END;

  END update_membre;


   PROCEDURE create_membre (
    lino NUMBER,                    -- numero de ligne versee
    m imp_cur%ROWTYPE              -- donnees derversees
   ) AS
   idcarteu donnees_carteu.id%TYPE; -- id de la carte associe au numero deverse
    membres_id membres.id%TYPE;     -- cle primaire du nouveau membre
    donnees_partenaire_id donnees_partenaire.id%TYPE; -- cle primaire des adhesions appli du client
  BEGIN
    log('WARN', lino, m.membre_identifiant || ' est nouvellement cree. l''utilisateur n''a pas de mdp.');

    -- insertion de la carte-u si elle n'existe pas encore
    IF idcarteu IS NULL THEN
      idcarteu := seq_donnees_carteu_id.nextval;
      INSERT INTO donnees_carteu (id, numero_carte)
      VALUES (idcarteu, m.numero_carte);
    END IF;

    -- cle primaire du nouveau membre est cle etrangere pour les infos associees
    membres_id := seq_membres_id.nextval;

    -- insertion du client lui-meme
    INSERT INTO membres (
      id,
      idrxp,
      email,
      identifiant,
      civilite,
      nom,
      prenom,
      naissancedate,
      profession,
      telfixe,
      telmobile,
      situationfamiliale,
      carteutypeporteur,
      carteu_porteur_principal,
      donnees_carteu_id
    ) VALUES (
      membres_id,
      m.membre_idrxp0,
      m.membre_email,
      m.membre_identifiant,
      m.membre_civilite,
      m.membre_nom,
      m.membre_prenom,
      m.membre_naissance,
      m.membre_profession,
      m.membre_tel_fixe,
      m.membre_tel_mobile,
      m.membre_situ_fam,
      m.membre_type_porteur,
      m.membre_porteur_principal,
      idcarteu
    );


      -- insertion de l'adresse domicile
      INSERT INTO donnees_adresses (
        membres_id,
        types_adresses_id,
        adresse,
        complement_adresse,
        code_postal,
        ville,
        pays
      ) VALUES (
        membres_id,
        types_adresses_map(m.adresse_type),
        m.adresse_street,
        m.adresse_complement,
        m.adresse_code_postal,
        m.adresse_ville,
        m.adresse_pays
      );

      -- insertion des souscriptions aux animations commerciales du client
      INSERT INTO donnees_communication (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      ) VALUES (
        membres_id,
        m.optin_sms,
        m.optin_sms_date,
        m.optin_sms_source,
        type_canal_map(m.optin_sms_canal)
      );

      INSERT INTO donnees_communication (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      ) VALUES (
        membres_id,
        m.optin_email,
        m.optin_email_date,
        m.optin_email_source,
        type_canal_map(m.optin_email_canal)
      );

      INSERT INTO donnees_communication (
        membres_id,
        accepte_canal,
        date_derniere_maj,
        source_maj,
        canal_communication_id
      ) VALUES (
        membres_id,
        m.optin_courrier,
        m.optin_courrier_date,
        m.optin_courrier_source,
        type_canal_map(m.optin_courrier_canal)
      );


    -- insertion des enfants
    IF m.enfant_1_prenom    IS NOT NULL OR
       m.enfant_1_sexe      IS NOT NULL OR
       m.enfant_1_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_1_prenom, m.enfant_1_sexe, m.enfant_1_naissance);
    END IF;

    IF m.enfant_2_prenom    IS NOT NULL OR
       m.enfant_2_sexe      IS NOT NULL OR
       m.enfant_2_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_2_prenom, m.enfant_2_sexe, m.enfant_2_naissance);
    END IF;

    IF m.enfant_3_prenom    IS NOT NULL OR
       m.enfant_3_sexe      IS NOT NULL OR
       m.enfant_3_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_3_prenom, m.enfant_3_sexe, m.enfant_3_naissance);
    END IF;

    IF m.enfant_4_prenom    IS NOT NULL OR
       m.enfant_4_sexe      IS NOT NULL OR
       m.enfant_4_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_4_prenom, m.enfant_4_sexe, m.enfant_4_naissance);
    END IF;

    IF m.enfant_5_prenom    IS NOT NULL OR
       m.enfant_5_sexe      IS NOT NULL OR
       m.enfant_5_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_5_prenom, m.enfant_5_sexe, m.enfant_5_naissance);
    END IF;

    IF m.enfant_6_prenom    IS NOT NULL OR
       m.enfant_6_sexe      IS NOT NULL OR
       m.enfant_6_naissance IS NOT NULL
    THEN
      INSERT INTO membre_enfants (membre_id, prenom, sexe, naissancedate)
      VALUES (membres_id, m.enfant_6_prenom, m.enfant_6_sexe, m.enfant_6_naissance);
    END IF;

    -- insertion des magasins favorites
    IF m.fav_magasinsu IS NOT NULL THEN
      INSERT INTO membres_types_magasins (membres_id, magasins_id, types_magasins_id)
      VALUES (membres_id, magasins_map(m.fav_magasinsu), types_magasins_map(m.fav_magasinsu_type));
    END IF;

    IF m.fav_mobileapp IS NOT NULL THEN
      INSERT INTO membres_types_magasins (membres_id, magasins_id, types_magasins_id)
      VALUES (membres_id, magasins_map(m.fav_mobileapp), types_magasins_map(m.fav_mobileapp_type));
    END IF;

    -- insertion du consentement transfert hors UE de donnees du client
    IF m.consentement_date IS NOT NULL THEN
      INSERT INTO membre_consentement (id_membre, date_consentement, id_source_consentement)
      VALUES (membres_id, m.consentement_date, partenaires_map(m.consentement_partenaire));
    END IF;

    -- insertion des inscriptions aux differentes applications
    IF m.adhesion_magasinsu_statut IS NOT NULL THEN
      donnees_partenaire_id := seq_donnees_part_id.nextval;

      INSERT INTO donnees_partenaire (
        id,
        statut_donnees_partenaire_id,
        partenaires_id
      ) VALUES (
        donnees_partenaire_id,
        statut_donnees_partenaire_map(m.adhesion_magasinsu_statut),
        partenaires_map(m.adhesion_magasinsu_partenaire)
      );

      INSERT INTO membres_donnees_partenaire (
        membres_id,
        donnees_partenaire_id
      ) VALUES (
        membres_id,
        donnees_partenaire_id
      );
    END IF;

    IF m.adhesion_mobileapp_statut IS NOT NULL THEN
      donnees_partenaire_id := seq_donnees_part_id.nextval;

      INSERT INTO donnees_partenaire (
        id,
        statut_donnees_partenaire_id,
        partenaires_id
      ) VALUES (
        donnees_partenaire_id,
        statut_donnees_partenaire_map(m.adhesion_mobileapp_statut),
        partenaires_map(m.adhesion_mobileapp_partenaire)
      );

      INSERT INTO membres_donnees_partenaire (
        membres_id,
        donnees_partenaire_id
      ) VALUES (
        membres_id,
        donnees_partenaire_id
      );
    END IF;

  END;

  PROCEDURE delete_membre (lino NUMBER, m imp_cur%ROWTYPE) IS BEGIN
    log('INFO', lino, m.membre_identifiant || ' est supprime par fusion');
    DELETE FROM donnees_adresses WHERE membres_id = m.old_membres_id2;
    DELETE FROM membres_types_magasins WHERE membres_id = m.old_membres_id2;
    DELETE FROM membre_consentement WHERE id_membre = m.old_membres_id2;

    -- cette action supprime en cascade les donnees associees des tableaux suivantes
    -- - donnees_personnelles
    -- - mot_de_passe_token
    -- - membre_enfants
    -- - donnees_communication
    -- - membres_donnees_partenaire
    DELETE FROM membres WHERE id = m.old_membres_id2;

   /* IF m.numero_carte != m.numero_carte2 THEN
      log('WARN', lino,
        m.membre_identifiant || ' change de carte-u: la ' ||
        m.numero_carte || ' remplace la ' ||
        m.numero_carte2 || ' devenant orphelin.'
      );
    END IF;*/
  END delete_membre;

-- -----------------------------------------------------------------------------
BEGIN
  dbms_output.enable(NULL); -- unlimited output

  -- mettre des donnees statiques / le referentiel en cache
  FOR row IN (SELECT id, code FROM magasins) LOOP magasins_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM type_canal) LOOP type_canal_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM partenaires) LOOP partenaires_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM types_adresses) LOOP types_adresses_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM types_magasins) LOOP types_magasins_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM statut_donnees_partenaire) LOOP statut_donnees_partenaire_map(row.code) := row.id; END LOOP;

  -- bulk collect afin de reduire le cout associe au changement
  -- de contexte entre le moteur sql et celui de scripting

  OPEN imp_cur;
  LOOP FETCH imp_cur BULK COLLECT INTO imp_tbl LIMIT imp_cur_max;
    EXIT WHEN imp_tbl.COUNT = 0;
    FOR lino IN 1..imp_tbl.COUNT LOOP
      imp_row := imp_tbl(lino);

      -- la centralisation de la donnee membre a pour consequence la fusion
      -- des anciennes entrees dont l'arbre decisionnel se trouve ci-dessous.

      IF imp_row.adhesion_magasinsu_statut IS NULL THEN
        log('ERROR', lino, imp_row.membre_identifiant || ' n''est pas associe a l''application magasins-u');

      -- #3
      ELSIF imp_row.membre_idrxp0 IS NULL THEN
        log('ERROR', lino, '1st rxp id is null');

      -- #2
      ELSIF imp_row.idrxp0 IS NOT NULL THEN
        update_membre(lino, imp_row, imp_row.old_membres_id0, imp_row.idcarteu0);

      ELSIF imp_row.idrxp0 IS NULL THEN

        IF imp_row.membre_idrxp1 IS NULL THEN

      -- #12
          IF imp_row.membre_idrxp2 IS NULL THEN
            create_membre(lino, imp_row);
      -- #9
          ELSIF imp_row.idrxp2 IS NULL THEN
            log('ERROR', lino, 'fusion d''ids RXP non-valide : 0=non-existant 1=vide 2=non-existant');
      -- #6
          ELSIF imp_row.idrxp2 IS NOT NULL THEN
            log('ERROR', lino,
              'fusion d''ids RXP non-valide : 0=non-existant 1=vide 2=existe. ' || 
              'ce 3eme (idx=2) est juge obsolete et donc rejete'
            );
          END IF;

        ELSIF imp_row.idrxp1 IS NULL THEN

      -- #11
          IF imp_row.membre_idrxp2 IS NULL THEN
            create_membre(lino, imp_row);
      -- #8
          ELSIF imp_row.idrxp2 IS NULL THEN
            create_membre(lino, imp_row);
      -- #5
          ELSIF imp_row.idrxp2 IS NOT NULL THEN
            update_membre(lino, imp_row, imp_row.old_membres_id2, imp_row.idcarteu2);
          END IF;

        ELSIF imp_row.idrxp1 IS NOT NULL THEN

      -- #10
          IF imp_row.membre_idrxp2 IS NULL THEN
            update_membre(lino, imp_row, imp_row.old_membres_id1, imp_row.idcarteu1);
      -- #7
          ELSIF imp_row.idrxp2 IS NULL THEN
            update_membre(lino, imp_row, imp_row.old_membres_id1, imp_row.idcarteu1);
      -- #4
          ELSIF imp_row.idrxp2 IS NOT NULL THEN
            delete_membre(lino, imp_row);
            update_membre(lino, imp_row, imp_row.old_membres_id1, imp_row.idcarteu1);
          END IF;
        END IF;
      END IF;
    END LOOP;
  END LOOP;
  CLOSE imp_cur;
END;

【问题讨论】:

您似乎缺少此块的 BEGIN ... END 部分的内容。您能否编辑问题以包含它?没有它,我可以从错误消息中真正说的是,您的代码在某处尝试在各种maps 之一中使用NULL 键。 你的代码应该看起来像DECLARE....BEGIN....END; --> 它被称为动态块。如果是程序,那么它应该是CREATE PROCEDURE...BEGIN...END; 但是看看你的代码,你的代码似乎是一些PACKAGE BODY 的sn-p。请编辑您的问题并添加整个代码。 @LukeWoodward:这是 SQL 的完整代码。 好吧,我没想到会有那么多代码。您的代码在 38 个位置从其中一个映射中查找值,其中任何一个都可能是问题所在。如果没有您的数据(请不要将其添加到问题中),我无法说出它是哪一个。恐怕您将不得不自己调试。我只能说,我之前关于其中一张地图的NULL 键的评论仍然有效。但是我会说,我希望错误消息包含一个堆栈跟踪,其中包含一个说明问题所在的行号。 不管怎样,下面的 LiveSQL 脚本重现了你的错误信息,并且还指出错误发生在第 5 行:livesql.oracle.com/apex/livesql/s/iphlmdlx8nbpsw37fdzjlgl85 【参考方案1】:

检查初始化块中的表格(如下)。验证列代码不包含任何空值,因为它被用作集合的索引。

  FOR row IN (SELECT id, code FROM magasins) LOOP magasins_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM type_canal) LOOP type_canal_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM partenaires) LOOP partenaires_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM types_adresses) LOOP types_adresses_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM types_magasins) LOOP types_magasins_map(row.code) := row.id; END LOOP;
  FOR row IN (SELECT id, code FROM statut_donnees_partenaire) LOOP statut_donnees_partenaire_map(row.code) := row.id; END LOOP;

【讨论】:

以上是关于ORA-06502: PL/SQL: 数字或值错误: NULL 索引表键值的主要内容,如果未能解决你的问题,请参考以下文章

ORA-06502: PL/SQL: 数字或值错误: 字符到数字的转换错误

ORA-06502: PL/SQL: 数字或值错误: NULL 索引表键值

ORA-06502: PL/SQL: 数字或值错误: 数字精度太大

获取 ORA-06502:PL/SQL:数字或值错误:SQL 触发器中的字符到数字转换错误

oracle ORA-06502:PL/SQL:数字或值错误:批量绑定:截断绑定

ORA - 06502:PL/SQL:数字或值错误:批量绑定:截断绑定