[ASP - Sql Server 2000] Défi pour trouver une requête complexe

Défi pour trouver une requête complexe [ASP - Sql Server 2000] - SQL/NoSQL - Programmation

Marsh Posté le 26-10-2005 à 09:27:08    

Bonjour,
 
Bon, je soumets mon problème dans un topic, parce que là, je m'enlise en fait.
 
J'explique (Je travaille en ASP donc, avec SqlServer 2000 derrière, serveur IIS évidemment).
 
J'ai une table dans ma bd, qui s'appelle Descripteur_Valeur. Elle sert à décrire deux types d'entités, les Granules et Manuels. Les manuels peuvent être composés de granules et des manuels, et les granules peuvent être composés de granules (des sous-granules en fait, mais pour le code, c'est la même chose).
 
Elle a la structure suivante :  
 
Descripteur_Valeur
 
Numero (Le numero du granule ou du manuel)
NomDescripteur (ben ça peut être Titre, Sujet, Date de création, Mots-Clefs, etc, etc)
Valeur (La valeur du descripteur donc)
TypeValeur (Indique s'il s'agit d'un Granule ou d'un Manuel, il peut donc prendre deux valeurs, Granule ou Manuel)
Ordre (Ne sert que pour le descripteur Parent...)
Valide (pour savoir si un granule ou manuel est en cours de création, et s'il a été validé ou non... Il n'apparaît à l'user final que s'il a ce champ à 1)
Obligatoire(Il y a quelques descripteurs obligatoires : Titre, Sujet, Date de création, Mots-Clefs, n° Version, les autres sont facultatifs)
 
Je dois faire une recherche avec des champs personnalisés, uniquement sur cette table.
 
 
Voici un aperçu (non trié du contenu de ma table, les colonnes dans l'ordre indiqué plus haut.
 

1 Auteur  Benjamin GRISTI  Granule 0 1 1
1 Auteur  Benjamin GRISTI  Manuel 0 1 1
1 Date de création 21/10/2005 16:07:10 Granule 0 1 1
1 Date de création 21/10/2005 16:28:13 Manuel 0 1 1
1 Dernière modific.. 21/10/2005 16:28:59 Manuel 0 0 1
1 Mots-Clefs au revoir   Granule 0 1 1
1 Mots-Clefs beta version  Manuel 0 1 1
1 Mots-Clefs bonjour   Granule 0 1 1
1 Mots-Clefs bonjour   Manuel 0 1 1
1 Mots-Clefs essai   Manuel 0 1 1
1 Mots-Clefs joli   Granule 0 1 1
1 Mots-Clefs nouveau   Granule 0 1 1


 
Voici un screenshot de ma page de recherche :  
 
http://img456.imageshack.us/img456/9889/screenhfr9qt.jpg
 
Donc ma recherche permet d'ajouter des champs de recherche, en fonction de ceux existant dans la base (dans mon exemple, il n'y a que des champs obligatoires, mais la recherche sera permis sur tous les Descripteurs existant dans la base.
 
Le + dans un champ de recherche permet la recherche de plusieurs valeurs d'un descripteur (1+2 dans le champ numéro permet de rechercher le granule 1 et le granule 2).
 
Ah au fait, la recherche, ici, ne concerne que les granules.
 
Voici donc, en asp, mon code permettant de générer la requete...
 


'Recupérer le tableau avec les champs de recherche rajoutés
TabDesc = Split(PreparePourBdd(Request.Form("listnewdesc" )), "," )
NbDesc = UBound(TabDesc)
 
'Le champ mots-clefs
TabMots = Split(Trim(MotsClefs), "+" )
NbMots = UBound(TabMots)
 
'Le champ numéro  
TabNum = Split(Trim(Numero), "+" )
NbNum = UBound(TabNum)
 
'La requete de base
Requete = _
"SELECT DISTINCT Numero " & _
"FROM Descripteur_Valeur " & _
"WHERE TypeValeur = 'Granule' " & _
"AND Valide = 1 "
 
'############# RECHERCHE DES NUMEROS DE GRANULES ####################
 
premiereligne = True
   
For i = 0 To NbNum
   
  If TabNum(i) <> "" Then
    If premiereligne Then
       
      Requete = Requete & _
        "AND (Numero = " & TabNum(i) & " "
       
      premiereligne = False
    Else
      Requete = Requete & _
        "OR Numero = " & TabNum(i) & " "
    End If
  End If
Next
   
If Numero <> "" Then
  Requete = Requete & " ) "
End If
   
premiereligne = True
 
'Et c'est sur la suite que ça bugue...
 
'############# RECHERCHE DE DESCRIPTEURS FACULTATIFS ####################
Dim RequeteTemp, premierdesc
   
RequeteTemp = Requete
premierdesc = True
   
Response.Write "<br>###########################<br>"
Response.Write Requete
Response.Write "<br>###########################<br>"
   
For i = 0 To NbDesc
   
  If TabDesc(i) <> "" Then
     
    TabTempDesc = Split(Request.Form("Desc_" & TabDesc(i)), "+" )
    NbTempDesc = UBound(TabTempDesc)
     
    If TabDesc(i) <> "" Then
       
      If premierdesc Then
       
        Requete = RequeteTemp & _
          "AND (NomDescripteur LIKE '%" & Replace(TabDesc(i),"#/", " " ) & "%' "
        premierdesc = False
       
      Else
       
        Requete = RequeteTemp & _
          "AND EXISTS ( " & _
          "SELECT * " & _
          "FROM Descripteur_Valeur " & _
          "WHERE Valide = 1 " & _
          "AND TypeValeur = 'Granule' " & _
          "AND (NomDescripteur LIKE '%" & Replace(TabDesc(i),"#/", " " ) & "%' "
      End If
       
    End If
     
    For j = 0 To NbTempDesc
       
      If premiereligne Then
       
        Requete = Requete & _
          "AND (Valeur LIKE '%" & TabTempDesc(j) & "%' "
       
        premiereligne = False
       
      Else
       
        Requete = Requete & _
          "OR Valeur LIKE '%" & TabTempDesc(j) & "%' "
       
      End If
       
     
    Next
     
    If TabDesc(i) <> "" Then
      Requete = Requete & " ) "
    End If
    Requete = Requete & " )"
     
  End If
     
  'premierdesc = True
  premiereligne = True
     
Next


 
Pour la requête INTERSECT aurait très bien fonctionné. Manque de pot, ça ne marche pas sous SqlServer. J'ai donc essayé le WHERE EXISTS, mais ça ne convient pas, les champs de recherche n'ayant pas d'ordre, le where exists se base sur le resultat de la requete qui le précède, et selon l'ordre, les résultats changent. Donc c'est mort.
 
Je dois impérativement trouver un moyen de faire cette recherche, détourné, ou bourrin même, sale, propre, peu importe, mais il le faut (et en plus il le faut avant mercredi prochain...)
 
Bref, si quelqu'un a le temps de s'atteler à mon problème, ça m'enleverai la tour eiffel qui est coincée dans mon petit orteil...
 
Merci d'avance.


Message édité par backdafuckup le 26-10-2005 à 09:53:02
Reply

Marsh Posté le 26-10-2005 à 09:27:08   

Reply

Marsh Posté le 26-10-2005 à 09:47:40    

J'ai pas trop le temps.
 
Déjà, c'est Windows 2000 ou 2003 et SQL Server 2000 ou 2005, mais pas SQL Server 2003 ;).
 
Sinon, j'ai vraiment pas le temps de lire en détail.
 
Pour moi, fais une fonction récursive (en T-SQL) qui permet, pour une ligne, d'aller voir si ça répond au mot clé, et se relance pour chaque granule liée. (et vu que c'est récursif, ça ira jusqu'au bout de la branche).
 
Seule limitation, la récursivité avec SQL Server 2000 (2005, je sais pas), c'est que ça n'accepte pas plus de 20 niveaux de profondeur (mais je doute que tu aies des sous-sous-sous...sous-granules sur 20 niveaux ;))
 
Ca te permettra de faire une requête très simple, tout en conservant des performances honnêtes, et en étant sûr de supporter tous les cas (y compris le sous-sous-granules), et avec une seule connection à SQL Server (donc infiniment mieu que X requêtes dans tes boucles, aussi optimisées soient-elles)


Message édité par Arjuna le 26-10-2005 à 09:54:35
Reply

Marsh Posté le 26-10-2005 à 09:48:51    

ps: quand je lis le contenu de ta table, je ne comprends pas comment tu gères la relation père/fils

Reply

Marsh Posté le 26-10-2005 à 09:50:47    

Après un coup d'oeil rapide, je crois comprendre qu'il s'agit d'un problème classique, où une ligne en sortie se base sur plusieurs lignes en entrée, et où il faut donc distinguer ces lignes avec des alias, par exemple D1 et D2. Ce qui done :

...
'La requete de base  
Requete = _  
"SELECT DISTINCT D1.Numero " & _  
"FROM Descripteur_Valeur D1" & _  
"WHERE D1.TypeValeur = 'Granule' " & _  
"AND D1.Valide = 1 "  
'############# RECHERCHE DES NUMEROS DE GRANULES ####################  
 
premiereligne = True  
   
For i = 0 To NbNum  
     
  If TabNum(i) <> "" Then  
    If premiereligne Then  
       
      Requete = Requete & _  
        "AND (D1.Numero = " & TabNum(i) & " "  
       
      premiereligne = False  
    Else  
      Requete = Requete & _  
        "OR D1.Numero = " & TabNum(i) & " "  
    End If  
  End If  
Next  
     
If Numero <> "" Then  
  Requete = Requete & " ) "  
End If  
     
premiereligne = True  
 
'Et c'est sur la suite que ça bugue...  
 
'############# RECHERCHE DE DESCRIPTEURS FACULTATIFS ####################  
Dim RequeteTemp, premierdesc  
     
RequeteTemp = Requete  
premierdesc = True  
     
Response.Write "<br>###########################<br>"  
Response.Write Requete  
Response.Write "<br>###########################<br>"  
     
For i = 0 To NbDesc  
     
  If TabDesc(i) <> "" Then  
       
    TabTempDesc = Split(Request.Form("Desc_" & TabDesc(i)), "+" )  
    NbTempDesc = UBound(TabTempDesc)  
       
    If TabDesc(i) <> "" Then  
       
      If premierdesc Then  
       
        Requete = RequeteTemp & _  
          "AND (D1.NomDescripteur LIKE '%" & Replace(TabDesc(i),"#/", " " ) & "%' "  
        premierdesc = False  
         
      Else  
         
        Requete = RequeteTemp & _  
          "AND EXISTS ( " & _  
          "SELECT * " & _  
          "FROM Descripteur_Valeur D2" & _  
          "WHERE  " & _  
          "   D2.Numero = D1.Numero " & _   ' ??? et peut-etre d'autres critères de jointures ???
          "AND D2.Valide = 1 " & _  
          "AND D2.TypeValeur = 'Granule' " & _  
          "AND (D2.NomDescripteur LIKE '%" & Replace(TabDesc(i),"#/", " " ) & "%' "  
      End If  
       
    End If  
       
    For j = 0 To NbTempDesc  
       
      If premiereligne Then  
       
        Requete = Requete & _  
          "AND (D1.Valeur LIKE '%" & TabTempDesc(j) & "%' "  
         
        premiereligne = False  
       
      Else  
       
        Requete = Requete & _  
          "OR D1.Valeur LIKE '%" & TabTempDesc(j) & "%' "  
       
      End If  
       
       
    Next  
       
    If TabDesc(i) <> "" Then  
      Requete = Requete & " ) "  
    End If  
    Requete = Requete & " )"  
     
  End If  
     
  'premierdesc = True  
  premiereligne = True  
     
Next  


Message édité par olivthill le 26-10-2005 à 09:52:27
Reply

Marsh Posté le 26-10-2005 à 09:59:51    

Arjuna a écrit :

ps: quand je lis le contenu de ta table, je ne comprends pas comment tu gères la relation père/fils


 
Merci pour le coup du 2000/2003. C'est donc bien sqlServer 2000 sous windows server 2003.
 
Imaginons un manuel (qu'on appelle Manuel1) qui a 4 fils , Granule1, 2, 3 et 4 dans cet ordre
 
on va donc avoir (les colonnes sont Numero, NomDescripteur, Valeur, TypeValeur, Ordre)
 
1  Parent  Manuel1  Granule  1 ...
2  Parent  Manuel1  Granule  2 ...
3  Parent  Manuel1  Granule  3 ...
4  Parent  Manuel1  Granule  4 ...
 
En fait tout se fait au niveau de l'enfant, et non du parent.
 
Je vais tester le coup des alias...

Reply

Marsh Posté le 26-10-2005 à 11:08:17    

Bon, ben les alias, dans l'état, ça fonctionne pas.
 
La je vais tenter autre chose : fonctionner avec des vues successives. A savoir une vue pour chaque champ de recherche... Et le suivant cherche dans la vue, et ainsi de suite...
 
Ca remplacera peut-être le INTERSECT.
 
Franchement, ce INTERSECT me paraît être une notion fondamentale, et au final, il n'est pas reconnu comme standard sql. Je trouve ça vraiment débile. C'est LE truc opposé à l'UNION, ça me paraît plutôt important mais bon...

Reply

Marsh Posté le 26-10-2005 à 11:54:00    

Bon, ben j'ai trouvé la solution.
 
C'était plutôt simple en fait.
 
Pour simuler l'INTERSECT j'ai utilisé IN
 

Dim RequeteTemp, premierdesc, closeparenthese
 
RequeteTemp = Requete
premierdesc = True
 
For i = 0 To NbDesc
 
If TabDesc(i) <> "" Then
 
TabTempDesc = Split(Request.Form("Desc_" & TabDesc(i)), "+" )
NbTempDesc = UBound(TabTempDesc)
 
premiereligne = True
 
Requete = Requete & _
"AND Numero IN (" & _
"SELECT Numero " & _
"FROM Descripteur_Valeur " & _
"WHERE Valide = 1 " & _
"AND TypeValeur = 'Granule' " & _
"AND NomDescripteur LIKE '%" & Replace(TabDesc(i),"#/", " " ) & "%' "
 
For j = 0 To NbTempDesc
 
If premiereligne Then
Requete = Requete & _
"AND (Valeur LIKE '%" & TabTempDesc(j) & "%' "
premiereligne = False
Else
Requete = Requete & _
"OR Valeur LIKE '%" & TabTempDesc(j) & "%' "
End If
 
Next
 
Requete = Requete & " )) "
End If  
 
Next


 
Donc, voici la requete si je fais une recherche avec les critères :  
Auteur LIKE 'ben'
Sujet LIKE '1'
 
SELECT DISTINCT Numero  
FROM Descripteur_Valeur  
WHERE TypeValeur = 'Granule'  
AND Valide = 1  
AND Numero IN  
    (SELECT Numero  
    FROM Descripteur_Valeur  
    WHERE Valide = 1  
    AND TypeValeur = 'Granule'  
    AND NomDescripteur LIKE '%Auteur%' AND (Valeur LIKE '%ben%' ))  
AND Numero IN  
    (SELECT Numero  
    FROM Descripteur_Valeur  
    WHERE Valide = 1  
    AND TypeValeur = 'Granule'  
    AND NomDescripteur LIKE '%Sujet%' AND (Valeur LIKE '%1%' ))
 
Et ainsi, mes clauses AND Numero IN s'ajoutent, et les résulats sont pour l'instant tous corrects.
 
Merci en tout cas de votre aide.
 
Est-ce que quelqu'un sait, au passage, pourquoi le INTERSECT ne fait-il pas partie de la norme SQL ?
Je veux dire, on l'apprend à l'école au même titre que l'UNION comme une opération VALIDE sur les ensembles.
 
Le produit, la division, l'union, l'intersection... J'invente rien !
 
Bref, ya une explication ?

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed