FAQ Loris

Paramétrage du client Loris

Administration Loris

SQL appliqué à Loris

SQL en général


Client Loris

Comment faire la différence entre test et prod ?

Lorsqu'on ouvre deux clients, l'un sur prod et l'autre sur test, on ne peut plus voir la différence.
Pour éviter ça, il suffit d'ouvrir le fichier doris.ini et de changer la variable NOMAPPLI.
Par exemple, pour la base test : NOMAPPLI=LORISTEST

Administration Loris

Comment régénérer tous les index de toutes les tables ?

Aller dans bin et faire : dt_index -u xxx/xxx -a A.LORIS -all_indexes

Comment se débarrasser des liens inverses lorsque ces liens ne sont pas inscrits dans DORIS_LNK ?

Par exemple : entre la table LECTEUR et la la table LINE_COMM.
La solution est de lancer : duqindex TABLE

Pourquoi duindexI EXEMPLAIRE ne produit-il pas l'index IEXEMPLAIRE attendu ?

Parce qu'il y a sans doute des exemplaires sans code-barre à cause de FTV. Il faut simplement les détruire avant de lancer duindexI.

Comment éliminer les lecteurs liés à des lignes de commande ?

1. Identifier les numéros des notices à éliminer et à mettre à jour
Ancien numéroNouveau numéro
xy
zNULL
2. Avec sqlplus

update LINE_COMM
set LECTEUR = &nouveau
where LECTEUR = &ancien;

commit;

3. duqindex pour régénérer les liens

duqindex LINE_COMM

4. Détruire les notices dans le clients

Comment vider un champ UNIMARC ?

On peut toujours utiliser perl lorsqu'une quantité énorme de notices (> 3000) est impactée.

Sinon, avec le client :

1. Créer un index sur le champ
2. Éteindre et redémarrer le serveur
3. Rechercher les notices à modifier dans Catalogue, et faire une modification globale
4. Détruire l'index.

Comment créer un index sur un code dans un champ composite ?

Il faut d'abord récupérer le code dans un champ normal, puis créer un index sur ce champ.
Par exemple, on peut récupérer le premier caractère du 105a (type d'illustrations) dans UNIMARC12 comme ceci :

  $UNIMARC12
    screen_name=Illustrations
    screen_name2=Unimarc12;
    len_maxi=70;
    concat=105a,1,1;
  

On fait ensuite un dureinit UNIMARC, puis on peut créer un index sur UNIMARC12 comme d'habitude.

Comment détruire les notices de la table MATIERE qui ne sont utilisées par aucune noticede la table UNIMARC ?

1. Régénérer la table Q_UNIMARC : duqindex UNIMARC
2. Identifier le numéro de la table MATIERE : select DORIS_KEY,UNAME from DORIS_UNIV where UNAME LIKE 'F%';
3. Lancer la requête :

	@csv.sql
	spool resultat.txt
	select doris_key from MATIERE
	where doris_key not in (select kintab from Q_UNIMARC where ktab=<Numéro de la table>);
	

Ou, plus radicalement :

	delete from MATIERE
	where doris_key not in (select kintab from Q_UNIMARC where ktab=<Numéro de la table>);
	

SQL

Comment détruire tous les fascicules d'un abonnement ?

  delete from FASCICULE
  where ABONNEMENT = &cle_abonnement;
  

&cle_abonnement est la DORIS_KEY de l'abonnement recherché.
Faire commit;, puis lancer un dulinks.

Comment détruire tous les fascicules et tous les abonnements d'un périodique ?

  delete from FASCICULE
  where ABONNEMENT IN
  (select DORIS_KEY from ABONNEMENT
  where ABONNEMENT.SITE_EMETTEUR = &bib
  and ABONNEMENT.PERIODIQUE LIKE '%,&cle_unimarc');
  

&bib est le code de la bibliothèque : parce que plusieurs bibliothèques peuvent avoir des abonnements liés à la même notice UNIMARC.
&cle_unimarc est la DORIS_KEY de la notice UNIMARC.
Faire commit;, puis lancer un dulinks.

Remarque : le champ ABONNEMENT.PERIODIQUE contient quelque chose comme : UNIMARC,93337

Comment effacer la "Date texte" de tous les fascicules liés à un abonnement ?

  update FASCICULE
  set COMPLEMENT_NUMERO = NULL
  where ABONNEMENT = &cle_abonnement;
  

&cle_abonnement est la DORIS_KEY de l'abonnement recherché.
Faire un commit;.

Comment recevoir une masse de fascicules ?

Il faut d'abord repérer les numéro des fascicules que l'on veut recevoir : dans le client, module Abonnements, onglet Recevoir, cliquer successivement sur le premier et le dernier fascicule que l'on veut recevoir et noter les DORIS_KEY.

  update FASCICULE
  set NBR_RECEPT = 1,DATE_RECEPT = DATE_LIVR_PREV
  where DORIS_KEY BETWEEN &cle_depart AND &cle_arrivee;
  

&cle_depart est la DORIS_KEY du premier fascicule à recevoir.
&cle_arrivee est la DORIS_KEY du dernier fascicule à recevoir.
Faire un commit;.
Note : DATE_RECEPT = DATE_LIVR_PREV : on met la date de réception à la date de livraison prévue.

Comment avoir tous les exemplaires de périodique qui ont un numéro d'inventaire ?

  select EXEMPLAIRE.DORIS_KEY from EXEMPLAIRE,UNIMARC
  where EXEMPLAIRE.INVENTAIRE IS NOT NULL
  and EXEMPLAIRE.LIVRE = UNIMARC.DORIS_KEY
  and UNIMARC.UNIMARC8 = 2;
  

C'est un simple exemple de jointure sur les tables UNIMARC et EXEMPLAIRE utilisant la valeur commune EXEMPLAIRE.LIVRE = UNIMARC.DORIS_KEY

Comment avoir les numéros de facture liés à un budget ?

Je veux savoir quels sont les numéros des factures payées sur mon budget CNL 2006 :
Le budget CNL 2006 a la fiche 102 dans la table BUDGET :

  select NUM_FACTURE from FACTURE
  where DORIS_KEY IN
  (SELECT FACTURE from LINE_FACT where LINE_COMM IN
  (SELECT DORIS_KEY from LINE_COMM where BUDGET_1 = 102));
  

Comment détruire les notices bibliographiques sans exemplaires et leurs lignes de commande non reçues ?

1. Détruire les notices bibliographiques :

  delete from UNIMARC
  where UNIMARC.DORIS_KEY IN
  (select UNIMARC.DORIS_KEY
  from UNIMARC,LINE_COMM,EXEMPLAIRE
  where UNIMARC.DORIS_KEY=SUBSTR(LINE_COMM.LIVRE,9)
  and LINE_COMM.UTIL_CREAT='cadet'
  and LINE_COMM.NBR_RECEPT=0
  and unimarc.doris_key=exemplaire.livre(+)
  and exemplaire.livre is null);
  

2. Détruire les lignes de commande :

  delete from LINE_COMM
  where LINE_COMM.UTIL_CREAT='cadet'
  and LINE_COMM.NBR_RECEPT=0;
  

3. Faire commit; puis dulinks.

Comment traiter les lecteurs0 ?

1. Ouvrir la table Prêts

2. Taper l'équation : KEY_LECT IS NULL

3. Pour chaque fiche, il faut remplacer deux champs :
- CODB_LECT : mettre le nouveau code-barre (cliquer sur le lien EXEMPLAIRE pour avoir le lecteur) ;
- KEY_LECT : taper le nom du lecteur puis %, et rapatrier le bon.

Comment identifier les exemplaires liés à des lecteurs disparus ?

  select DORIS_KEY from EXEMPLAIRE
  where LECTEUR NOT IN
  (select DORIS_KEY from LECTEUR);
  

Quelles sont les requêtes SQL lancées par Loris ?

1. Réabonnement

Dans l'onglet Réabonner, quand on lance une recherche, la requête équivalente est : ETAT_REABON = 0 AND SITE_EMETTEUR = 1 (avec un WHERE sur les mots du titre).

Comment lister des notices bibliographiques en fonction des notices d'exemplaires liées ?

Si on lance une simple requête avec jointure, on récupère 2 notices bibliographiques si la notice est liée à 2 exemplaires. Par exemple :

  select count(*) from UNIMARC,EXEMPLAIRE
  where UNIMARC.FR_BN = '022760180'
  and UNIMARC.DORIS_KEY = EXEMPLAIRE.LIVRE;
  

Si la notice a deux exemplaires, on reçoit la réponse : 2. Comment obtenir 1 ? Réponse :

  select count(*) from UNIMARC
  where DORIS_KEY in
  (select DISTINCT UNIMARC.DORIS_KEY
  from UNIMARC,EXEMPLAIRE
  where UNIMARC.FR_BN = '022760180'
  and UNIMARC.DORIS_KEY = EXEMPLAIRE.LIVRE);
  

Toutes mes notices sont en Nouveautés ! Comment ne mettre en Nouveautés que les acquisitions des quinze derniers jours ?

  update UNIMARC
  set UNIMARC13 = 0
  where UNIMARC.DORIS_KEY IN
  (select EXEMPLAIRE.LIVRE from EXEMPLAIRE
  where EXEMPLAIRE.DATE_ACQUIS < 20120220);
  

Vérifications avant récolement

Pour éviter l'affreux message d'erreur au moment du récolement :

erreur_recolement (17K)

1. Vérifier qu'il n'y a pas de champ CODE_BARRE sans valeur :

  select DORIS_KEY from EXEMPLAIRE
  where CODE_BARRE IS NULL;
  

2. Vérifier qu'il n'y a pas de doublons dans le champ CODE_BARRE :

  select CODE_BARRE, COUNT(*) from EXEMPLAIRE
  GROUP BY CODE_BARRE
  HAVING COUNT(*) > 1;
  

Comment tirer la liste des codes-barres absents de Loris ?

À partir d'une longue liste de codes-barres, comment savoir ceux qui ne sont pas dans la table EXEMPLAIRE ?
Cette question n'a pas de solution en SQL (SELECT ne peut pas renvoyer une valeur qu'il ne trouve pas). Mais on peut faire ça en PL/SQL et en perl : voir ici.

Comment ajouter un nouveau type de prêt pour toutes la catégories de lecteurs ?

On peut le faire à la main : dupliquer la fiche pour chaque catégorie de lecteur. C'est long.

On peut le faire avec PL/SQL. Exemple :

  DECLARE
   CURSOR mesdroits IS
    SELECT * FROM DROITS
    WHERE SUPPORT = 16 AND BIBLIOTHEQUE = 2;
   mon_droit DROITS%ROWTYPE;
   cle NUMBER(10);
  BEGIN
   SELECT MAX(DORIS_KEY) INTO cle FROM DROITS;
   OPEN mesdroits;
   LOOP
    cle := cle + 1;
    FETCH mesdroits INTO mon_droit;
    INSERT INTO DROITS (DORIS_KEY,BIBLIOTHEQUE,CATEGORIE,SUPPORT,NOMBRE_PRET,DUREE_JOUR,NOMBRE_PLACE,DUREE_HEURE,RESERVATION,MISE_DISPO,NB_PROLONG,NB_PROLONG_EX,DUREE_PROLONG,NOMBRE_NEW,DUREE_NEW,RESA_NEW,DISPO_NEW,PROLONG_NEW,PROLONG_NEW_EX,DUREE_PROLONG_NEW,PERIODE_AMENDE,DEBUT_AMENDE,DELAI_POSTAL_REL1,AMENDE,AMENDE_MAX,DELAI_GRACE,AMENDE_JOUR,AMENDE_JOUR_MAX,DELAI_GRACE_JOUR,DELAI_REL0,DELAI_REL1,DELAI_REL2,DELAI_REL3,DELAI_REL4,DELAI_REL5,TYPE_INSCRIPTION,MONTANT_INSCRIPTION,DUREE_INSCRIPTION,DATE_FIN,ID1,ID2,ID3,ID4)
    VALUES(cle,'1',mon_droit.CATEGORIE,mon_droit.SUPPORT,mon_droit.NOMBRE_PRET,mon_droit.DUREE_JOUR,mon_droit.NOMBRE_PLACE,mon_droit.DUREE_HEURE,mon_droit.RESERVATION,mon_droit.MISE_DISPO,mon_droit.NB_PROLONG,mon_droit.NB_PROLONG_EX,mon_droit.DUREE_PROLONG,mon_droit.NOMBRE_NEW,mon_droit.DUREE_NEW,mon_droit.RESA_NEW,mon_droit.DISPO_NEW,mon_droit.PROLONG_NEW,mon_droit.PROLONG_NEW_EX,mon_droit.DUREE_PROLONG_NEW,mon_droit.PERIODE_AMENDE,mon_droit.DEBUT_AMENDE,mon_droit.DELAI_POSTAL_REL1,mon_droit.AMENDE,mon_droit.AMENDE_MAX,mon_droit.DELAI_GRACE,mon_droit.AMENDE_JOUR,mon_droit.AMENDE_JOUR_MAX,mon_droit.DELAI_GRACE_JOUR,mon_droit.DELAI_REL0,mon_droit.DELAI_REL1,mon_droit.DELAI_REL2,mon_droit.DELAI_REL3,mon_droit.DELAI_REL4,mon_droit.DELAI_REL5,mon_droit.TYPE_INSCRIPTION,mon_droit.MONTANT_INSCRIPTION,mon_droit.DUREE_INSCRIPTION,mon_droit.DATE_FIN,mon_droit.ID1,mon_droit.ID2,mon_droit.ID3,mon_droit.ID4);
    EXIT WHEN mesdroits%NOTFOUND;
   END LOOP;
   CLOSE mesdroits;
  END;
  

Ce script duplique chaque notice de la table DROITS pour le SUPPORT 16 et la BIBLIOTHEQUE 2, et crée une copie de chaque fiche pour la BIBLIOTHEQUE 1.
Pour le lancer, le plus simple est de faire un fichier avec vi, puis de l'appeler avec sqlplus : le lancer avec /.
À l'issue, faire commit;, puis un durenit DROITS.

Attention : il y a un défaut, la dernière notice est copiée une fois de trop, il y a donc une erreur renvoyée par dureinit. Il faut détruire à la main la notice surnuméraire.

Comment lister les codes-barres dont la longueur est différente de 10 ?

Dans le client Loris, table EXEMPLAIRE, entrer simplement (pour Draguignan) :

  length(CODE_BARRE) <> 10 and bibliotheque = 4
  

Faire ensuite un export en Excel.

Astuces SQL

Comment extraire les lignes d'une table qui ne sont liées qu'à une seule autre ligne d'une autre table ?

C'est un problème que l'on rencontre lorsque l'on veut par exemple uniquement les notices qui n'ont qu'un seul exemplaire.

1. Une solution assez élégante est d'utiliser une sous-requête :

  select T.LIVRE from
  (select LIVRE,COUNT(*) from EXEMPLAIRE
  GROUP BY LIVRE HAVING COUNT(*)=1)T;
  

La sous-requête renvoie un ensemble que l'on nomme T et dont on extrait le champ LIVRE.

Si on a besoin d'autres champs, il faut utiliser cette requête comme critère (IN, ALL, SOME) :

  SELECT EXEMPLAIRE.LIVRE||'$$'||EXEMPLAIRE.FONDS||'$$'||EXEMPLAIRE.COTE||'$$'||EXEMPLAIRE.CODE_BARRE||'$$'||EXEMPLAIRE.ETAT
  FROM EXEMPLAIRE
  WHERE EXEMPLAIRE.LIVRE IN
  (select T.LIVRE from
  (select LIVRE,COUNT(*) from EXEMPLAIRE
  GROUP BY LIVRE HAVING COUNT(*)=1)T);
  

Cela renvoie les données d'exemplaire pour les notices qui n'ont qu'un seul exemplaire.

On peut aussi utiliser le résultat de cette requête directement dans un WHERE ... IN comme ceci :

  SELECT FTV_UNIMARC.NUM_NOTICE||'$$'||EXEMPLAIRE.FONDS||'$$'||EXEMPLAIRE.COTE||'$$'||EXEMPLAIRE.CODE_BARRE||'$$'||EXEMPLAIRE.ETAT
  FROM FTV_UNIMARC,EXEMPLAIRE
  WHERE FTV_UNIMARC.DORIS_KEY IN
  (select T.LIVRE from
  (select LIVRE,COUNT(*) from EXEMPLAIRE
  GROUP BY LIVRE HAVING COUNT(*)=1)T)
  AND FTV_UNIMARC.DORIS_KEY = EXEMPLAIRE.LIVRE;
  

2. Une autre solution, mais en passant par un autre langage (perl, asp...), est de tout récupérer en triant selon le champ voulu, puis d'imprimer/afficher seulement lorsque la ligne suivante est différente de la ligne précédente (en conservant la donnée critère dans une variable et en testant à chaque ligne suivante).

Comment limiter la réponse d'Oracle à un nombre donné de lignes ?

Il suffit d'ajouter une condition sur ROWNUM. Exemple :

  select doris_key from UNIMARC
  where FR_BN like 'U%' and UNIMARC26 IS NULL
  and rownum <=10;
  

Cette requête ne renvoie que 10 lignes.

Attention : si on veut une réponse triée, il faut trier avant :

  select * from
  (select doris_key from UNIMARC
  where FR_BN like 'U%' and UNIMARC26 IS NULL
  order by doris_key)
  where rownum <=10;
  

Et si on veut un intervalle de lignes (de la 10e à la 15e) :

  select doris_key from
  (select doris_key, ROWNUM num
     from
     (select doris_key from UNIMARC
     where FR_BN like 'U%' and UNIMARC26 IS NULL
     order by doris_key)
  )
  where num between 1 and 10;
  

Cette requête est équivalente à la précédente, mais plus souple, puisqu'on peut définir un intervalle.

À ce sujet, voir ici.

Comment mettre à jour les données d'une table en fonction d'une autre table ?

Voici un schéma bien compliqué (issu de Wikipedia) :

  UPDATE TABLE1
  SET   (colonne3, colonne4) = (SELECT colonne32, colonne13 
                                FROM   TABLE2 
                                WHERE  TABLE1.colonneX = TABLE2.colonneY)
  WHERE  colonneZ IN (SELECT col FROM TABLE2)
  

Exemples :

  UPDATE FASCICULE
  SET FASCICULE.DATE_ARELANCER =
  (SELECT TO_CHAR((TO_DATE(FASCICULE.DATE_LIVR_PREV,'YYYYMMDD') + (ABONNEMENT.DELAI1 * 2)),'YYYYMMDD')
  FROM ABONNEMENT
  WHERE ABONNEMENT.DORIS_KEY = FASCICULE.ABONNEMENT)
  WHERE FASCICULE.ETAT_RELANCE = 1
  AND FASCICULE.ABONNEMENT IN (SELECT ABONNEMENT.DORIS_KEY FROM ABONNEMENT);
  
  UPDATE DSTAT
  SET COUNT12 = (SELECT LECTEUR.FACULTE
  FROM LECTEUR
  WHERE DSTAT.TEXT2 = LECTEUR.NUMERO_CARTE)
  WHERE COUNT12 IS NULL
  AND DSTAT.TEXT2 IN (SELECT LECTEUR.NUMERO_CARTE FROM LECTEUR);
  

Remettre la bonne DORIS_KEY des lecteurs dans les prêts, en fonction du numéro de carte lecteur enregistré dans chaque prêt :

  update PRET
  set KEY_LECT = (select LECTEUR.DORIS_KEY
  from LECTEUR
  where PRET.CODB_LECT = LECTEUR.NUMERO_CARTE)
  where PRET.CODB_LECT in (select LECTEUR.NUMERO_CARTE from LECTEUR);
  

Remettre le bon lecteur dans les exemplaires prêtés : on va chercher le lecteur dans la table des prêts en cours.

	update exemplaire
  set lecteur =
    (select key_lect from pret
    where exemplaire.code_barre = pret.codb_exemp)
  where lecteur not in (select doris_key from lecteur);
	

Comment utiliser une jointure avec des fonctions comme SUM ?

1. Voici une solution :

  SELECT
      TABLE2.CHAMP1,TABLE2.CHAMP2,
      (SELECT SUM(TABLE1.CHAMP2)
       FROM TABLE1
       WHERE TABLE2.CHAMP1 = TABLE1.CHAMP1)
  FROM
      TABLE2
  

2. Une autre solution souvent plus pratique est d'utiliser une view.
Par exemple, je veux connaître la distribution par fonds des notices locales.
Je crée d'abord une view :

  create or replace view unimarc26 (BIB, LOC)
  as select EXEMPLAIRE.BIBLIOTHEQUE,EXEMPLAIRE.FONDS
  from EXEMPLAIRE,UNIMARC
  WHERE UNIMARC26 = 1
  AND EXEMPLAIRE.LIVRE = UNIMARC.DORIS_KEY
  WITH READ ONLY;
  

Puis je lance la requête sur cette view :

  select bib,loc,count(*)
  from unimarc26
  group by bib, loc;
  

Autre exemple : je veux la liste des doublons de SORT dans la table MATIERE, puis je veux les DORIS_KEY de ces SORT. Voici la solution, qu'on peut écrire dans un seul fichier (sort_matiere.sql) et qu'on appelle en une seule commande (@sort_matiere.sql) :

  create or replace view sort_matiere (ID, TOTAL)
  as select SORT,COUNT(*) from MATIERE
  group by SORT
  HAVING COUNT(*) > 1
  WITH READ ONLY;
  
  @csv.sql
  spool sort_matiere.txt
  select MATIERE.doris_key from MATIERE, SORT_MATIERE
  where MATIERE.SORT in (select SORT_MATIERE.ID from SORT_MATIERE)
  and MATIERE.SORT = SORT_MATIERE.ID;
  

Comment faire une jointure sur plus de deux tables ?

Il suffit de multiplier les AND pour s'assurer de faire le lien entre chaque table.
Voici par exemple une simple requête sur la table PRET qui récupère en même temps un champ de LECTEUR et un champ de EXEMPLAIRE :

  select PRET.DORIS_KEY, EXEMPLAIRE.DORIS_KEY, LECTEUR.DORIS_KEY
  from PRET, EXEMPLAIRE, LECTEUR
  where PRET.ETAT_RELANCE = 1 and PRET.BIBLIOTHEQUE = 2
  and PRET.KEY_LECT = LECTEUR.DORIS_KEY
  and PRET.KEY_EXEMP = EXEMPLAIRE.DORIS_KEY
  

Comment récupérer un champ qui n'est pas directement lié à la table interrogé ?

C'est la suite de la requête ci-dessus : à partir de la table PRET, je veux récupérer le DISPLAY de UNIMARC, qui n'est nullement lié à PRET, mais que l'on peut atteindre à travers EXEMPLAIRE.LIVRE qui se trouve dans PRET, dans le champ PRET.CODB_EXEMP.
Comme ci-dessus, la solution est de multiplier les AND, même sur les tables UNIMARC et EXEMPLAIRE qui sont éloignées de PRET :

  select PRET.COTE, PRET.CODB_EXEMP, PRET.DATE_RELANCE, UNIMARC.DISPLAY, LECTEUR.NOM, LECTEUR.PRENOM, PRET.CODB_LECT
  from PRET, UNIMARC, LECTEUR, EXEMPLAIRE
  where PRET.ETAT_RELANCE = 1 AND PRET.BIBLIOTHEQUE = 2
  and PRET.KEY_LECT = LECTEUR.DORIS_KEY
  and PRET.KEY_EXEMP = EXEMPLAIRE.DORIS_KEY
  and EXEMPLAIRE.LIVRE = UNIMARC.DORIS_KEY;
  

Récupérer les notices dont tous les exemplaires récents sont en prêt

Pour faire ça, il faut faire une sous-requête corrélée (correlated subquery) :

  select EXEMPLAIRE.LIVRE, COUNT(*)
  from EXEMPLAIRE
  where EXEMPLAIRE.ETAT = 2
  and EXEMPLAIRE.BIBLIOTHEQUE = 1
  and EXEMPLAIRE.ETAT = ALL(select B.ETAT
  from EXEMPLAIRE B
  where B.BIBLIOTHEQUE = 1
  and B.DATE_ACQUIS > 20120101
  and B.LIVRE = EXEMPLAIRE.LIVRE)
  GROUP BY EXEMPLAIRE.LIVRE
  HAVING COUNT(*) > 1;
  

La sous-requête est corrélée grâce à la condition and B.LIVRE = EXEMPLAIRE.LIVRE.
Pour chaque réponse à la première requête, le système relance la sous requête. Donc, pour chaque notice (LIVRE), on regarde les exemplaires liés et on ne garde la notice que si TOUS (ALL) les exemplaires liés répondent aux critères.