[VB/TSQL/SQL-Server] Mes questions sur les Procédures stockées

Mes questions sur les Procédures stockées [VB/TSQL/SQL-Server] - SQL/NoSQL - Programmation

Marsh Posté le 16-05-2007 à 16:05:55    

EDIT : Histoire de pas blinder le forum de plein de topics différents, je vais poser toutes mes questions ici. Le problème évoqué dans le 1er post est résolu, merci de vous rendre à la fin du topic pour connaître mon problème actuel, merci d'avance ;)
 
 
 
 
Salut à tous
 
Je travaille sur une courte mission et je débarque totalement dans ce domaine, donc j'aimeraiss quelques conseils de spécialistes ;)
 
Voici ma procédure stockée :
 

CREATE PROCEDURE MaProcedure
(
@identifiant char(9)
)
AS
 
DECLARE
@champ1 char(4),
@champ2 char(2)
 
SELECT
   @identifiant = identifiant
   @champ1 = champ1
   @champ2 = champ2
 
FROM
   MaTable
 
WHERE
   @identifiant = identifiant
 
If @@Rowcount < 1
SELECT
   @identifiant = 0
GO


 
Appel de la procédure en VB :
 

Set Rs = SQL_ExecuteReqPS(Obj, PBL_Conn, "MaProcedure", colAller, , , 0)


 
Le but de cette procédure est simple : on cherche un enregistrement unique dans une table via l'identifiant passé en paramètre; si on le trouve la procédure retourne l'identifant et les champs 1 et 2, et si on ne le trouve pas on retourne juste l'identifant avec pour valeur "0"
 
Maintenant pour les questions :

  • La structure et la syntaxe vous semblent-elles correctes ? (je peux pas encore vraiment tester) (résolu)
  • La procédure va-t-elle bien faire ce que j'ai décrit juste au dessus ?
  • Comment récupérer les champs du RecordSet dans mon programme VB ? (je crois que c'est Rs("champ1" ) ou un truc du genre)


Plz help :bounce:


Message édité par Kirvel le 31-05-2007 à 11:04:44

---------------
MyAnimeList
Reply

Marsh Posté le 16-05-2007 à 16:05:55   

Reply

Marsh Posté le 16-05-2007 à 17:14:17    

un ptit up avant le week-end ;)


---------------
MyAnimeList
Reply

Marsh Posté le 18-05-2007 à 01:12:56    

Ouh là là...
 
Non, ça fait absolument pas ce que tu dis que ça va faire...
 
Là, tu viens écraser @identifiant passé en paramètre "IN" (donc en lecture seule) avec une valeur. Ceci est absolument pas bon du tout, je suis étonné que t'arrive même à compiler ou lancer ta fonction.
 
Pour @champ1 et @champ2, étant déclarés localement, ça va jamais les retourner !
 
Bouge pas, je teste un truc et je poste un truc qui marche (de toute façon, vu l'heure, tu dois pioncer ferme, tu risques pas de bouger :D)

Reply

Marsh Posté le 18-05-2007 à 01:25:06    

Le procédure correcte (avec jeu de test complet) :

Code :
  1. CREATE TABLE toto (id int, nom nvarchar(50), age int)
  2. go
  3. INSERT INTO toto VALUES (1, 'MagicBuzz', '28')
  4. go
  5. CREATE procedure maprocedure
  6. (
  7.   @identifiantcherche int,
  8.   @identifianttrouve int output,
  9.   @champ1 nvarchar(50) output,
  10.   @champ2 int output
  11. )
  12. AS
  13. begin
  14.   SELECT
  15.      @identifianttrouve = id,
  16.      @champ1 = nom,
  17.      @champ2 = age
  18.   FROM toto
  19.   WHERE id = @identifiantcherche
  20.  
  21.   IF @@ROWCOUNT = 0
  22.   begin
  23.      SET @identifianttrouve = 0
  24.      SET @champ1 = NULL
  25.      SET @champ2 = NULL
  26.   end
  27. end
  28. go
  29.  
  30. declare @a int
  31. declare @b int
  32. declare @c nvarchar(50)
  33. declare @d int
  34. SET @a = 1
  35. execute maprocedure @a, @b output, @c output, @d output
  36. print @b
  37. print isnull(@c, 'null')
  38. print isnull(cast(@d AS nvarchar), 'null')
  39. print '---------------'
  40. SET @a = 2
  41. execute maprocedure @a, @b output, @c output, @d output
  42. print @b
  43. print isnull(@c, 'null')
  44. print isnull(cast(@d AS nvarchar), 'null')


 
Et le code VBScript : ('tain j'en ai chié grave, j'ai plus l'habitude de faire du VBS moi :o)

Code :
  1. Option Explicit
  2.  
  3. Dim cnx, cmd, p1, p2, p3, p4
  4. Dim a, b, c
  5.  
  6. const adCmdProc = 4
  7.  
  8. const adInteger = 3
  9. const adVarWChar = 202
  10.  
  11. const adParamInput = 1
  12. const adParamOutput = 2
  13.  
  14. Set cnx = CreateObject("ADODB.Connection" )
  15. cnx.ConnectionString = "Provider=sqloledb;Data Source=(local);Initial Catalog=test;Integrated Security=SSPI;"
  16. cnx.Open
  17. Set cmd = CreateObject("ADODB.Command" )
  18. Set cmd.ActiveConnection = cnx
  19. cmd.CommandText = "maprocedure"
  20. cmd.CommandType = adCmdProc
  21. cmd.NamedParameters = True
  22.  
  23. Set p1 = cmd.CreateParameter()
  24. p1.Name = "@identifiantcherche"
  25. p1.Type = adInteger
  26. p1.Direction = adParamInput
  27. p1.Value = 1
  28. Set p2 = cmd.CreateParameter()
  29. p2.Name = "@identifianttrouve"
  30. p2.Type = adInteger
  31. p2.Direction = adParamOutput
  32. Set p3 = cmd.CreateParameter()
  33. p3.Name = "@champ1"
  34. p3.Type = adVarWChar
  35. p3.Size = 50
  36. p3.Direction = adParamOutput
  37. Set p4 = cmd.CreateParameter()
  38. p4.Name = "@champ2"
  39. p4.Type = adInteger
  40. p4.Direction = adParamOutput
  41. cmd.Parameters.Append p1
  42. cmd.Parameters.Append p2
  43. cmd.Parameters.Append p3
  44. cmd.Parameters.Append p4
  45. cmd.Execute
  46.  
  47. If p2.Value = 0 Then
  48.   MsgBox "Element non trouvé"
  49. Else
  50.   MsgBox "Element trouvé : " & p2.Value & " - " & p3.Value & " - " & p4.Value
  51. End If
  52.  
  53. p1.Value = 2
  54. cmd.Execute
  55.  
  56. If p2.Value = 0 Then
  57.   MsgBox "Element non trouvé"
  58. Else
  59.   MsgBox "Element trouvé : " & p2.Value & " - " & p3.Value & " - " & p4.Value
  60. End If
  61.  
  62. Set cmd = Nothing
  63. cnx.Close
  64. Set cnx = Nothing


Message édité par MagicBuzz le 18-05-2007 à 02:09:49
Reply

Marsh Posté le 18-05-2007 à 02:04:01    

ok merci, c pas facile de faire des procédures stockées quand on y a pas été formé [:cerveau erf]
 
Les print c juste pour de l'affichage ?
 
EDIT : je teste çà lundi, pour l'instant c'est le week-end [:cosmoschtroumpf]


Message édité par Kirvel le 18-05-2007 à 02:04:42

---------------
MyAnimeList
Reply

Marsh Posté le 18-05-2007 à 02:08:45    

-- tiens, tu dormais pas :D --
 
je remonte le topic pour afficher mes corrections ;)
 
oui, print ça fait juste de l'affichage, c'est pour le test dans sql query editor. toi tout ce qui t'intéresse, c'est la partie entre "create procedure" et "end"
 
pour plus d'info sur la manipulation des objets parameter et command, va sur ce site (ça va faire 10 ans que je m'en sert au moins une fois par moi ;))
http://www.devguru.com <- section "ADO"

Reply

Marsh Posté le 18-05-2007 à 15:35:46    

Merci pour tes réponses, je pense qu'avec tout ça j'ai tout ce qu'il me faut pour pouvoir m'en sortir lundi. Sinon c pas du VBS que j'utilise c du VB (bien que je connaisse pas vraiment les différences) ... [:cerveau cupra]


---------------
MyAnimeList
Reply

Marsh Posté le 20-05-2007 à 20:43:27    

sa procédure est correcte, du moins ça fonctionne avec SQL SERVER 2005...
 
On peut acraser une variable passé en paramètre. Aucun problème à ce niveau la. Elles sont passé par copie de toute façon (IN).
 
Pour ce qui est de rembaler la valeur, en SQL SERVER 2005 suffit de faire un RETURN de ta variable locale.  
 
Même si on est dans une procédure, ça marche, mais faut exécuter un executeScalar (avec C# par exemple) pour correctement la récupérer.  
 
Ce que je dis est valable pour SQL SERVER 2005, je n'ai jms bossé avec les versions antérieurs.

Message cité 1 fois
Message édité par moi23372 le 20-05-2007 à 20:44:52
Reply

Marsh Posté le 21-05-2007 à 09:34:14    

moi23372 a écrit :

sa procédure est correcte, du moins ça fonctionne avec SQL SERVER 2005...
 
On peut acraser une variable passé en paramètre. Aucun problème à ce niveau la. Elles sont passé par copie de toute façon (IN).


Le souci, c'est que sans "return", le paramètre ne prends pas la valeur modifiée. Car comme tu dis, elle est passée en copie et non en référence. Du coup, on arrive à un comportement inatendu. C'est le même qu'en VB d'ailleurs, où les paramètres en entrée ne sont pas en lecture seule. En ADA par exemple, c'est protégé : tout en ce qui passé en "in" est en lecture seule. En C# (et VB.NET) il me que c'est aussi protégé. Ou il doit y avoir un warning à la compilation.
 
Enfin bref, il vaut mieu éviter de venir écraser une variable passée en paramète sans le mot-clé "ouput", car le comportement risque d'être inatendu, surtout pour une personne habituée à traîter ces paramètres comme lecture seule.
 
Pour ce qui est de faire un "return" sur une "procedure", je trouve ça goret aussi, de la même façon. Une procédure ne retourne sémantiquement rien. Autant utiliser comme dans mon exemple une série de variables "output". C'est plus propre.


Message édité par MagicBuzz le 21-05-2007 à 09:37:03
Reply

Marsh Posté le 21-05-2007 à 09:36:44    

Sinon, entre VBS et VB, pas de différences majeures.
 
- Utilisation de "CreateObject" en VBS : En VB, même si ça marche, on préférera lier les bibliothèques au projet
- Utilisation de variables non typées en VBS : En VB, on peut typer les variables. En VBS c'est impossible. Utilise donc le typage.
 
Pour le reste, là y'a rien qui vient. Si, byref qui n'existe pas en VBS, ainsi que d'autres trucs. M'enfin bref, copier/coller de mon code dans VB6 doit marcher. Par contre, je t'invite à le rendre un peu plus propre et conforme à VB6 ;)

Reply

Marsh Posté le 21-05-2007 à 09:36:44   

Reply

Marsh Posté le 21-05-2007 à 10:47:02    

Merci pour votre aide je pense que ça ira pour ma procédure ;)
 
Maintenant je me bats avec Visual Studio pour faire un 1er test unitaire ... Je trouve pas le moyen de simuler un appel de mon module ActiveX avec les paramètres et tout ...


---------------
MyAnimeList
Reply

Marsh Posté le 21-05-2007 à 14:40:52    

Petite question sur les lignes 8 à 10 de ta procédure stockée MagicBuzz :
 
Les variables sont certes en OUTPUT mais elles sont déclarées comme paramètres de la procédure, et donc à son appel elle s'attend à recevoir ces paramètres, alors que je ne lui envoie que l'identifiant ...
En fait j'ai pas encore bien saisi les syntaxes possibles pour les paramètres que la procédure stockée reçoit et ceux qu'elle retourne.
 


Message édité par Kirvel le 21-05-2007 à 14:41:05

---------------
MyAnimeList
Reply

Marsh Posté le 21-05-2007 à 17:25:53    

C'est tout bon, mon programme VB et ma procédure stockée fonctionnent de bout en bout.
 
Merci encore pour votre aide [:cerveau jap]
 
EDIT : Voilà ce que j'ai fait au final :
 


CREATE PROCEDURE dbo.MaProcedure
(
 @identifiant_Param Char(9)
)
AS
 
BEGIN
 SELECT identifiant, champ1, champ2
 FROM  MaTable
 WHERE identifiant = @identifiant_Param
END
GO


 
Finalement c'était d'une simplicité affligente ... Mais ça me permet de faire tout ce que je voulais : si l'identifiant n'est pas trouvé je fais un test sur RecordSet.EOF dans mon programme VB et si c'est à TRUE ça veut dire qu'il n'a rien trouvé. Simple comme bonjour ...
Mais forcément quand on débarque et qu'on voit plein d'exemples partout on cherche à faire pareil alors qu'au final c'est beaucoup plus simple qu'on ne le pense :sarcastic:


Message édité par Kirvel le 21-05-2007 à 17:31:49

---------------
MyAnimeList
Reply

Marsh Posté le 22-05-2007 à 09:34:42    

Sauf que là, c'est sale...
Y'a que SQL Server qui ramène les lignes retrouvées à l'intérieur d'une PS. De plus, si demain la PS change pour faire un appel à une fonction par exemple, qui ne retourne pas le lignes, t'es baisé. Tout comme si demain elle exécute deux requêtes de suite pour faire une vérification supplémentaire.
 
Regarde mon exemple. Je colle des paramètres pour les output, et je les relis. Un bête copier/coller de mon code FONCTIONNE sous VB (t'as juste à adapter la connexion string).
Base-toi sur cet exemple, c'est la syntaxe propre, qui te garanti une compatibilité avec n'importe quelle version de SQL Server ou autre SGBD.

Reply

Marsh Posté le 22-05-2007 à 10:44:11    

Pour le code VB j'ai dû utiliser des fonctions déjà existantes pour l'appel de ma PS et j'avais un problème avec les paramètres en OUTPUT pour lesquels on me demandait des valeurs en INPUT, ce dont je n'ai pas besoin ... J'aurais aimé mettre en place une procédure sur le modèle de la tienne mais comme je suis sur une mission relativement courte et qu'il y a encore pas mal de boulot derrière je reste sur cette solution pour l'instant. Si jamais par la suite j'arrive à mieux comprendre ces histoires d'appels de PS et que j'ai le temps de m'y pencher un plus, j'hésiterai pas à en changer ;)
 
Merci encore pour le temps que tu as consacré à mon problème : même si je n'ai pas repris ton code, ça m'a permis de piger quelques petits trucs qui m'ont bien aidé ;)


Message édité par Kirvel le 22-05-2007 à 10:44:25

---------------
MyAnimeList
Reply

Marsh Posté le 22-05-2007 à 14:07:57    

Y'a pas de valeur INPUT pour un paramètre OUTPUT.
 
Par contre, comme dans mon exemple, il faut les binder avec des PARAMETER, qui vont prendre les valeurs de sortie.
 
Suffit de lire mon code. Les paramètres p2, p3 et p3, je leur affecte jamais de .Value, par contre une fois la PS appelée, c'est eux que je vais lire pour voir ce que m'a retourné la procédure...

Reply

Marsh Posté le 30-05-2007 à 14:35:02    

Je reprends mon topic histoire de pas en créer plein ...
 
Toujours concernant les procédures stockées, je veux créer la mienne en me basant sur d'autres PS déjà existantes, et dans l'une d'elles j'ai ça :
 

 set @query = 'SELECT DISTINCT H.NOIDPR, H.NOIDLE,  
 H.CORISQ,
 ''' + @xx + ''', ''G1''  
 from ' + @xx + '..G1_ID_DECOMPTE H  


 
Ce qui me dérange là dedans, c toutes ces simples-quotes qui s'enchaînent ... Moi je suis habitué au principe du \' mais là je vois pas trop ce que je vais avoir au final dans ma variable @query ... J'arrive pas à saisir la logique de lecture ...
 
help plz, expliquez-moi comment je dois lire ça [:cerveau dawa psycho]


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 11:16:46    

Aujourd'hui nouveau problème (en plus de celui d'hier sur les simples-quotes pour lequel j'attend toujorus une réponse :hello: )
 
 
Toujours en TSQL dans une procédure stockée :
 

Code :
  1. CASE
  2. WHEN (  @p_TypSaisie = 0
  3.    AND (@p_NoLot = '' OR @p_NoLot IS NULL)
  4.    AND (@p_NoFac = '' OR @p_NoFac IS NULL)
  5.    AND (@p_NoINSEE = '' OR @p_NoINSEE IS NULL) ) THEN
  6.   -- Requete 1
  7.  SELECT
  8.   Deco.DATRT2, Deco.DACRLO, Deco.DAARFS, Deco.NOLOT, Deco.NOFATI, Dest.NOPOUV,
  9.   Dest.MTSSDE, Dest.MTRCDE, Deco.TYPSAIS
  10.  FROM
  11.   ( @xx..G1_DESTINATAIRE AS Dest
  12.                      INNER JOIN @xx..G1_DECOMPTE AS Deco ON
  13.     Dest.NOSLIQ = Deco.NOSLIQ
  14.    AND Dest.DASDEC = Deco.DASDEC
  15.    AND Dest.NOLIQU = Deco.NOLIQU
  16.    AND Dest.NOGRTR = Deco.NOGRTR
  17.    AND Dest.NOLIAS = Deco.NOLIAS
  18.    AND Dest.NOORDE = Deco.NOORDE
  19.    AND Dest.NOTRLI = Deco.NOTRLI )
  20.  INNER JOIN @xx..G1_ID_DECOMPTE AS IDD ON
  21.     Deco.NOSLIQ = IDD.NOSLIQ
  22.    AND Deco.DASDEC = IDD.DASDEC
  23.    AND Deco.NOLIQU = IDD.NOLIQU
  24.    AND Deco.NOGRTR = IDD.NOGRTR
  25.    AND Deco.NOLIAS = IDD.NOLIAS
  26.    AND Deco.NOORDE = IDD.NOORDE
  27.    AND Deco.NOTRLI = IDD.NOTRLI
  28.  WHERE
  29.   Deco.DATRT2 BETWEEN STR(@p_DateDeb,8) AND STR(@p_DateFin,8)
  30.      AND Dest.NOIDDE = @p_NoAssure
  31.      AND Deco.TYPSAIS IN (0,1)


 
L'erreur qu'il me sort c'est : Syntaxe incorrecte vers le mot clé 'CASE'.
 
Quand je mets SELECT CASE, alors il me dit : Syntaxe incorrecte vers le mot clé 'CASE'. (mais pour celui qui est 6 lignes plus bas ... )
 
Quand je mets SELECT CASE 1, alors il me dit : syntaxe incorrecte vers '='.
 
 
Bref je voudrais savoir comment faire un CASE, sachant que dans chacun de mes WHEN il y a une requête différente à exécuter. ... oui, une belle question de noob, mais quand on connaît pas la syntaxe [:spamafote]

Message cité 1 fois
Message édité par Kirvel le 31-05-2007 à 11:24:03

---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 11:54:27    

Kirvel a écrit :

Je reprends mon topic histoire de pas en créer plein...


Le forum est blindé de topic (donc 80% sans aucun intérêt ni pour celui qui pose la question ni pour ceux qui y répondent) mais pourtant il est bien plus aisé de suivre l'évolution du forum en se référant aux nouveaux topics plutôt que de voir un topic déterré refaire surface : de nombreuses personnes ne vont même pas le lire, en se disant "encore un qui sait pas lire et qui veut qu'on lui réexplique ce qu'on a passé 10 pages à expliquer..." ;)
 
Bon, je m'en retourne lire ton problème :)

Reply

Marsh Posté le 31-05-2007 à 11:59:41    

Kirvel a écrit :

Ce qui me dérange là dedans, c toutes ces simples-quotes qui s'enchaînent ... Moi je suis habitué au principe du \' mais là je vois pas trop ce que je vais avoir au final dans ma variable @query ... J'arrive pas à saisir la logique de lecture ...
 
help plz, expliquez-moi comment je dois lire ça [:cerveau dawa psycho]


D'ailleurs, ça confirme ce que je disais... J'ai passé la soirée hier et ce matin à passer sur le forum, et j'avais pas vu cette question :D
 
La norme SQL est différente de la norme ANSI en ce qui concerne l'échappement des caractères.
Certains SGBD supportent les deux (Oracle, MySQL, etc.) mais d'autre ne supportent que le SQL Strict (SQL Server, Access, etc.)
 
La norme SQL est très simple, c'est la même qui a été adoptée en Visual Basic par exemple : j'ai un caractère à la con ? Je l'échappe en le doublant :
 
pour écrire un ' dans une chaîne de caractère, je le remplace par ''.
pour écrire un % dans un LIKE, je le remplace par %% etc.
 
Ce qui donne donc :
 
set @query = 'SELECT DISTINCT H.NOIDPR, H.NOIDLE,  H.CORISQ, ''' + @xx + ''', ''G1'' from ' + @xx + '..G1_ID_DECOMPTE H'
 
Avec @xx = "toto" :
 
select distinct h.noidpr, h.noidle, h.corisq, 'toto', 'G1' from toto..g1_id_decompte h
 
(j'imagine que @xx est le nom d'une base de données non ?)

Reply

Marsh Posté le 31-05-2007 à 12:04:03    

Kirvel a écrit :

L'erreur qu'il me sort c'est : Syntaxe incorrecte vers le mot clé 'CASE'.


CASE attend une valeur pour effectuer les tests.
Idem, WHEN attends des constantes
 
C'est exactement comme le switch en C :
 

Code :
  1. swicth (var)
  2. {
  3.  case "A":
  4.     // do the A thing
  5.     break;
  6.  case "B":
  7.     // do the B thing
  8.     break;
  9.  default:
  10.     // do the rest
  11. }


 
Ca se traduit en T-SQL :
 

Code :
  1. CASE @var
  2.  WHEN 'A' THEN
  3.    -- Do the A thing
  4.  WHEN 'B' THEN
  5.    -- Do the B thing
  6.  ELSE
  7.    -- Do the rest
  8. END


 
EDIT :
J'ai dit une connerie :ange:
 
D'après la doc :

Code :
  1. Simple CASE FUNCTION:
  2. CASE input_expression
  3.     WHEN when_expression THEN result_expression
  4.    [ ...n ]
  5.     [
  6.    ELSE else_result_expression
  7.     ]
  8. END
  9. Searched CASE FUNCTION:
  10. CASE
  11.     WHEN Boolean_expression THEN result_expression
  12.    [ ...n ]
  13.     [
  14.    ELSE else_result_expression
  15.     ]
  16. END


 
Donc ta syntaxe devrait marcher...
 
En fait, trouvé :
 

Code :
  1. declare @var1 AS varchar(1);
  2. declare @var2 int;
  3.  
  4. SET @var1 = NULL;
  5. SET @var2 = 0;
  6.  
  7. SELECT case
  8. when @var1 IS NULL AND @var2 > 0 then
  9.  SELECT count(*) FROM uti
  10. when @var1 IS NULL AND @var2 = 0 then
  11.  SELECT count(*) FROM pays
  12. else
  13.  SELECT count(*) FROM meuble
  14. end;


=> Marche pas
 
Mais...

Code :
  1. declare @var1 AS varchar(1);
  2. declare @var2 int;
  3.  
  4. SET @var1 = NULL;
  5. SET @var2 = 0;
  6.  
  7. SELECT case
  8. when @var1 IS NULL AND @var2 > 0 then
  9.  (SELECT count(*) FROM uti)
  10. when @var1 IS NULL AND @var2 = 0 then
  11.  (SELECT count(*) FROM pays)
  12. else
  13.  (SELECT count(*) FROM meuble)
  14. end;


=> Marche. Il faut mettre ta requête entre () pour ça ça marche, pour faire comprendre à l'interpréteur que c'est ton select qui doit être mis en résultat.
 
Effectivement, à l'exécution, il va retenir cette requête au final :

Code :
  1. SELECT (SELECT count(*) FROM pays)


 
Si on ne met pas les (), il se dit "ouh là là, deux select de suite, y va pas bien le gars" ;)
 
 
Pour en revenir à ton cas, pourquoi tu utilises CASE ? On dirait que tu n'as qu'un cas... Utilise un IF à la place, et tu pourras faire tout ce que tu veux comme tests ;)
 
IF <tests>
BEGIN
  -- Trucs à faire quand les tests vont bien
END
ELSE
BEGIN
  -- Trucs à faire quand ça foire
END


Message édité par MagicBuzz le 31-05-2007 à 12:17:02
Reply

Marsh Posté le 31-05-2007 à 12:17:19    

@xx est bien un nom de base de données
 
pour l'histoire de l'échappement j'étais resté sur '' = \' . Donc c'est un peu ça finalement :)
 
Sinon le case que j'ai mis plus haut je n'ai mis qu'1 seul WHEN pour pas spammer la page, parce qu'en fait j'en ai 18 des requêtes dans mon CASE :whistle:  
Sinon je viens de passer pas mal de temps à me renseigner sur le mot clé CASE, et apparemment en TSQL on peut pas l'utiliser en dehors d'une requête, et il faudrait donc que je me rabatte sur du IF/ELSEIF ... Mais ça me parait bizarre quand même, c'est quand même bien pratique un CASE :??:  
 
Je verrai ça cet après-midi, c'est l'heure de manger [:nico54]


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 12:18:37    

PS : Le CASE ne peut apparement s'utiliser que dans une requête contrairement à IF qui ne peut s'utilise que comme statement T-SQL.


Message édité par MagicBuzz le 31-05-2007 à 12:19:18
Reply

Marsh Posté le 31-05-2007 à 12:19:48    

Kirvel a écrit :

@xx est bien un nom de base de données
 
pour l'histoire de l'échappement j'étais resté sur '' = \' . Donc c'est un peu ça finalement :)


c'est même complètement ça ;)

Reply

Marsh Posté le 31-05-2007 à 12:20:53    

Kirvel a écrit :

@xx est bien un nom de base de données
 
pour l'histoire de l'échappement j'étais resté sur '' = \' . Donc c'est un peu ça finalement :)
 
Sinon le case que j'ai mis plus haut je n'ai mis qu'1 seul WHEN pour pas spammer la page, parce qu'en fait j'en ai 18 des requêtes dans mon CASE :whistle:  
Sinon je viens de passer pas mal de temps à me renseigner sur le mot clé CASE, et apparemment en TSQL on peut pas l'utiliser en dehors d'une requête, et il faudrait donc que je me rabatte sur du IF/ELSEIF ... Mais ça me parait bizarre quand même, c'est quand même bien pratique un CASE :??:  
 
Je verrai ça cet après-midi, c'est l'heure de manger [:nico54]


ben...
 
select *
from (case ...) as t
=> Ca va faire ce que tu veux :D
 
PS : Et relis mon post d'avant je l'ai complèté et corrigé ;)

Reply

Marsh Posté le 31-05-2007 à 12:24:21    

Je viens de lire ton EDIT, les parenthèses ont l'air de fonctionner mais maintenant il me dit :
syntaxe incorrecte vers '.' à la ligne : @xx..G1_DESTINATAIRE AS Dest
 
Là je comprends vraiment pas parce que c'est bien comme ça qu'on désigne une base de donnée ... à moins que ça soit la variable @xx qui le dérange ...


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 12:54:24    

il faut la construire comme dans ta question précédente, et utiliser alors un exec.

Reply

Marsh Posté le 31-05-2007 à 13:44:14    

MagicBuzz a écrit :

il faut la construire comme dans ta question précédente, et utiliser alors un exec.


 
C'est ce que j'avais fait au départ ... Je faisais mon SELECT FROM, puis je construisais mon WHERE au fur et à mesure dans une chaîne, mais par la suite j'ai discuté avec un mec du service BdD et le 1er truc qu'il m'a dit c'est : "Qui c'est qui a codé ce charabia ?"
En gros il me dit qu'en construisant la requête on est obligé de "recompiler" la requête à chaque fois qu'on l'appelle car elle sera quasi-toujours différente et que niveau performance c'est pas ce qu'il y a de mieux car on perd l'avantage de l'utilisation d'une procédure stockée. C'est lui qui m'a conseillé de faire plusieurs requêtes différentes mais invariables et que l'on appelle en fonction des paramètres envoyés. Comme ça, une fois la requête appelée une première fois, plus besoin de la "recompiler" et gain de performance.
 
NB. : Je dis recompiler mais je ne sais plus le terme exact qu'il m'a donné. C'était une histoire de plan de charge je crois ... Bref, l'équivalent des DECLARE, PREPARE, OPEN, EXECUTE, CLOSE en Oracle.
 
EDIT : Je vais faire ça avec des IF/ELSEIF et ça devrait aller ... mais je ne crois pas que ça résoudra le problème de mon post précédent sur la variable @xx


Message édité par Kirvel le 31-05-2007 à 13:51:52

---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 14:10:40    

Je suis 100% d'accord avec ce que ton pote à dit.
 
Donc soit tu fais un EXEC tout pourri et tu peux utiliser une variable comme nom de base, soit tu fais autant de requêtes qu'il y a de base, et tu lances la bonne requête en fonction de ta variable.
 
Dans tous les cas, je pige pas trop pourquoi t'as 36 bases avec visiblement un modèle identique... A mon avis, c'est les tables qu'il faut repenser, afin d'inclure un champ discriminent qui permet d'éviter d'avoir 36 bases de données.
 
T'es chez Econocom avec François Roché ou quoi ? (le gars qui utilise Access, fait "enregistrer" => "voulez-vous créer un champ identifiant dans votre table ?" et qui te sors ça comme seul argument pour dire qu'il faut mettre des numéroauto en pk dans toutes les tables plutôt que d'utiliser des pk propres ou des clés composites -et à cause de ça, se retrouver avec 50 bases de données sur le même serveur, parcequ'il ne voulait pas rajouter un champ "codsoc" permettant d'identifier au niveau de la PK dans quelle société on travaillait :pt1cable:) <- ça m'a traumatisé.


Message édité par MagicBuzz le 31-05-2007 à 14:12:52
Reply

Marsh Posté le 31-05-2007 à 14:28:38    

En fait le principe des différentes bases c'est que chacune correspond à un mois comptable :
la base 0 c'est le mois en cours, la base 1 c'est janvier 2006, base 2 février 2007, etc le tout sur 2 ans (ou 4), et quand on arrive à une fin de mois comptable on écrase la base la plus ancienne avec la base 0 et on repart en base 0 avec le nouveau mois comptable ...
 
L'architecture est telle qu'elle est depuis certainement plus longtemps que je ne suis dans le monde du travail, donc c pas un intérimaire qui n'est là que depuis 3 semaines comme moi qui va la refaire.
 
 
Sinon en gros tu me dis : soit j'utilise un "exec @query" et je peux utiliser ma variable @xx, soit je fais mon IF/ELSEIF et faut que je réécrive mes 18 requêtes autant de fois que j'ai de bases ?
 
Si c'est ça je laisse tomber direct et je reprends mon code initial qui tenait en 30 lignes ... Surtout que pour le faire ce code je m'étais déjà inspiré de PS existantes et qui elles non plus n'étaient pas optimisées niveau performance ! Certes je ne connais pas leur contexte d'utilisation mais bon ... pas moyen que j'écrive 48*18 fois la même requête avec à chaque fois 2 caractères qui changent :pfff:

Message cité 1 fois
Message édité par Kirvel le 31-05-2007 à 14:31:39

---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 14:31:37    

Bienvenue dans un système mis en place par un écervelé qui se croyait certainement très fort... :sweat:
 
Pis alors 18 mois d'historique (si j'ai bien compris) ça c'est bien total n'importe quoi...

Reply

Marsh Posté le 31-05-2007 à 14:35:00    

Non non c 2 ou 4 ans d'historique !
18 c le nombre de clauses WHERE possibles :p
 
Quant à la taille de l'historique, ça ne me parait pas aberrant ... tout dépend du métier :o


Message édité par Kirvel le 31-05-2007 à 14:35:20

---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 14:36:55    

Kirvel a écrit :

Sinon en gros tu me dis : soit j'utilise un "exec @query" et je peux utiliser ma variable @xx, soit je fais mon IF/ELSEIF et faut que je réécrive mes 18 requêtes autant de fois que j'ai de bases ?


 
Alors ? C'est bien ça que tu me dis ? Tu es sûr qu'il n'y a pas d'autre moyen ?


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 15:26:06    

J'ai demandé conseil à la personne du service BdD qui m'a fait la remarque hier sur les performances, et voici sa réponse :
 

Citation :

OK, tu fais  accès aux différentes bases de la info profressionnelle censurée …
J’avais oublié ce détail .
Dans ce cas tu n’as pas d’autres choix que le SQL dynamique (ce que tu m’avais montré initialement fera l’affaire).
Désolé de t’avoir envoyé sur une mauvaise piste.


 
Ca fait plaisir de perdre toute 1 journée dans le zeff sur une mission courte d'interim déjà pas évidente et en fonction de laquelle je peux avoir un CDI si ça se passe bien ... :fou:  
 
M'enfin bon ... j'ai appris des trucs, j'ai pas complètement perdu mon temps non plus :o
 
 
Fin du débat, je repasserai sûrement par là si je rencontre d'autres problèmes. Merci à toi MagicBuzz
 

Spoiler :

un rapport avec Magic Bus ?


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 16:35:35    

Et le nouveau problème n'a pas tardé à se montrer ! Voici ma PS initiale :
 

Code :
  1. ALTER  PROCEDURE dbo.RQTR_INT_MISESENPAIMENT_CR
  2. @p_NoAssure INT,
  3. @p_DateDeb INT,
  4. @p_DateFin INT,
  5. @p_NoLot INT,
  6. @p_NoFacture INT,
  7. @p_NoINSEE INT,
  8. @p_TypSaisie SMALLINT
  9. AS
  10. DECLARE
  11. @liste  VARCHAR(240),
  12. @excmd  VARCHAR(400),
  13. @query  VARCHAR(8000),
  14. @stret  INT,
  15. @xx  VARCHAR(3),
  16. @yy  SMALLINT
  17. SET NOCOUNT ON
  18. SET CONCAT_NULL_YIELDS_NULL OFF
  19. SET @yy = 1
  20. EXEC @stret = dbo.smp_scan_bases_on_dates 'SAISIE', @p_DateDeb, @p_DateFin, @liste OUT
  21. IF @@error <> 0
  22.  RETURN
  23. SET rowcount 0
  24. PRINT @liste
  25. WHILE ( @stret >  0 )
  26. BEGIN /*  BEGIN of WHILE  */
  27. SELECT @stret = @stret - 1
  28. SELECT @xx = RTRIM ( SUBSTRING ( @liste, @yy, 3 ) )
  29. SELECT @yy = @yy +4
  30. EXEC ( 'set nocount on' )
  31. SET @query = ' SELECT
  32.    Deco.DATRT2, Deco.DACRLO, Deco.DAARFS, Deco.NOLOT, Deco.NOFATI,
  33.    Dest.NOPOUV, Dest.MTSSDE, Dest.MTRCDE, Deco.TYPSAIS
  34.   FROM
  35.    (' + @xx + '..G1_DESTINATAIRE AS Dest
  36.                             INNER JOIN ' + @xx + '..G1_DECOMPTE AS Deco ON
  37.     Dest.NOSLIQ = Deco.NOSLIQ
  38.    AND Dest.DASDEC = Deco.DASDEC
  39.    AND Dest.NOLIQU = Deco.NOLIQU
  40.    AND Dest.NOGRTR = Deco.NOGRTR
  41.    AND Dest.NOLIAS = Deco.NOLIAS
  42.    AND Dest.NOORDE = Deco.NOORDE
  43.    AND Dest.NOTRLI = Deco.NOTRLI )
  44.     INNER JOIN ' + @xx + '..G1_ID_DECOMPTE AS IDD ON
  45.     Deco.NOSLIQ = IDD.NOSLIQ
  46.    AND Deco.DASDEC = IDD.DASDEC
  47.    AND Deco.NOLIQU = IDD.NOLIQU
  48.    AND Deco.NOGRTR = IDD.NOGRTR
  49.    AND Deco.NOLIAS = IDD.NOLIAS
  50.    AND Deco.NOORDE = IDD.NOORDE
  51.    AND Deco.NOTRLI = IDD.NOTRLI
  52.   WHERE
  53.     Deco.DATRT2 BETWEEN ' + STR(@p_DateDeb,8) + ' AND ' + STR(@p_DateFin,8)
  54.       + ' AND Dest.NOIDDE = ' + @p_NoAssure
  55. IF ( @p_NoINSEE IS NOT NULL ) AND ( @p_NoINSEE <> '' )
  56.  SET @query = @query + ' AND IDD.NOINSE = ' + @p_NoINSEE
  57. IF NOT ( @p_TypSaisie = 2 AND ( @p_NoLot <> '' AND @p_NoLot IS NOT NULL AND @p_NoFacture <> '' AND @p_NoFacture IS NOT NULL ) )
  58. BEGIN   -- Sinon le Type de saisie n est plus un critere de selection
  59.  SET @query = @query + ' AND ( '
  60.  IF @p_TypSaisie = 0 OR @p_TypSaisie = 2  -- Traitements automatiques
  61.  BEGIN
  62.   SET @query = @query + ' ( Deco.TYPSAIS IN (0,1) '
  63.   IF @p_Nolot <> '' AND @p_NoLot IS NOT NULL
  64.    SET @query = @query + ' AND Deco.NOLOT = ' + @p_NoLot
  65.   IF @p_NoFacture <> '' AND @p_NoFacture IS NOT NULL
  66.    SET @query = @query + ' AND Deco.NOFAC = ' + @p_NoFacture
  67.   SET @query = @query + ' ) '
  68.  END
  69.  IF @p_TypSaisie = 2
  70.   SET @query = @query + ' OR '
  71.  IF  @p_TypSaisie = 1 OR @p_TypSaisie = 2  -- Traitements manuels
  72.   SET @query = @query + ' ( Deco.TYPSAIS > 1 ) '
  73.  SET @query = @query + ' ) '
  74. END
  75. PRINT @query
  76. EXEC ( @query )
  77. IF @@error <> 0
  78. BEGIN
  79.  SELECT @excmd = 'Probleme requete >> ' + RTRIM(@query) + ' <<RQTR_INT_MISESENPAIEMENT_CR '
  80.  RAISERROR ( @excmd, 16, 1 ) WITH SETERROR
  81.  RETURN 99
  82. END
  83. END /* END of WHILE */
  84. PRINT 'REQUETE FINIE'
  85. GO


 
et voilà l'erreur qu'il me sort :
 

Citation :

Erreur de syntaxe lors de la conversion de la valeur varchar ' SELECT
    Deco.DATRT2, Deco.DACRLO, Deco.DAARFS, Deco.NOLOT, Deco.NOFATI,
    Dest.NOPOUV, Dest.MTSSDE, Dest.MTRCDE, Deco.TYPSAIS FROM
    (B0..G1_DESTINATAIRE AS Dest
                             INNER JOIN B0..G1_DECOMPTE AS Deco ON
     Dest.NOSLIQ = Deco.NOSLIQ
    AND Dest.DASDEC = Deco.DASDEC
    AND Dest.NOLIQU = Dec...
B0 +


 
C'est quoi cette erreur ? Un problème de concaténation ou alors ma requête qui est foireuse quelque part ? (genre dans la construction du WHERE, ce qui ne m'étonnerait pas)


Message édité par Kirvel le 05-06-2007 à 13:36:36

---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 16:40:14    

euh... isole le bout de code qui merde, parceque là, c'est pas possible de trouver d'où ça vient comme ça...
 
duplique la PS.
 
change en @query = 'select 1'
et rajoute des petits bouts au fur et à mesure jusqu'à ce que tu produise l'erreur...

Reply

Marsh Posté le 31-05-2007 à 16:46:07    

pas bête, je regarde ça


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 16:52:43    

Kirvel a écrit :

pas bête, je regarde ça


8 ans d'expérience, ça aide :D

Reply

Marsh Posté le 31-05-2007 à 17:03:06    

Apparemment ça vient de la ligne 64 ... Je comprends pas trop le problème mais je vais creuser un peu, merci pour l'astuce.


---------------
MyAnimeList
Reply

Marsh Posté le 31-05-2007 à 17:07:08    

et voilà ... un test entre un VARCHAR(9) et un INT ...
Oracle ça le dérangeait pas ça ...


---------------
MyAnimeList
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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