29-08-2017, 01:41 PM
Salut,
ce n'est pas l'usage d'une procédure. Une procédure effectue un traitement, et retournera 0, 1 ou plusieurs "resultsets". Il ne fait donc pas sens de mettre la procédure dans un SELECT.
Comme tu l'as découvert, il existe d'autres moyens de faire ce que tu souhaites:
1) L'usage d'une fonction
Ce principe est simple à mettre en place, et consiste à créer "un truc" similaire à une procédure, mais qui ne renverra non pas 0, 1 ou plusieurs resultsets mais uniquement 1 seule valeur scalaire. Tu peux alors utiliser cette fonction partout où une valeur scalaire peut apparaitre, à condition de passer à cette fonction les paramètres dont elle a besoin. Tu peux donc faire un SELECT myFunction(1234, t.x, t.y) FROM table AS t, ce qui aura pour effet de prendre toutes les lignes de la table, de calculer myFunction(...) pour chaque ligne, et de retourner la liste de ces résultats (sous la forme d'un resultset). Tu peux également l'utiliser dans un WHERE, façon SELECT * FROM table AS t WHERE myFunction(1234, t.x, t.y) = 2. Attention dans ce cas aux performances, car l'utilisation d'un index ne sera pas possible (sauf en passant par les colonnes virtuelles du dernier MySQL, éventuellement)
2) L'usage d'une vue
C'est très très similaire comme résultat, mais complètement différent comme façon de penser: une vue est simplement une table SQL, qui n'est pas stockée sur le serveur (en tous cas, pas chez MySQL, Oracle a une notion de "vues stockées", identique au système de vue à la seule différence que le SGBD se permet de stocker la vue sur le disque s'il estime que ce sera plus rapide), et qui est donc calculée à la volée, lors de la requête. Elle se présente comme donc comme une table, dont le contenu est le résultat d'un SELECT.... Par exemple, tu peux créer la vue myView correspondant à la requête SELECT (t.x+t.y)/1234 FROM table AS t. Faire un SELECT sur cette vue sera alors comme faire le SELECT correspondant à cette vue (ie: SELECT * FROM myView revient à faire SELECT (t.x+t.y)/1234 FROM table AS t ).
Du coup, les deux cas répondent à deux besoins différents:
• La fonction est pratique si le traitement est complexe, et utilisé dans des contextes totalement différents (par exemple, si le "1234" n'est pas constant, mais dépend d'autre choses). Par exemple, une fonction distance2d(x,y) retournant RETURN SQRT(x*x+y*y) est une bonne utilisation des fonctions, si celle-ci est réutilisée un peu partout dans différentes tables. C'est aussi utilisable (je crois, à vérifier en pratique) s'il y a des sous-requêtes à faire dans ladite fonction (mais là, les perfs, ouch, ça peut faire mal: tu verras à l'usage)
• La vue est pratique si le traitement est simple et n'est pas réutilisé dans d'autres contextes. Par exemple, SELECT *, (c.x*c.x + c.y*c.y) AS dist2d FROM mapcases AS c est une vue parfaitement acceptable. Note que la vue peut elle-même se servir de la fonction (SELECT *, distance2d(c.x, c.y) AS dist2d FROM mapcases).
Dans ton cas, je pense que la vue pourrait être plus adaptée: je doute que tu réutilises ta fonction ailleurs qu'ici, et je pense que tu apprécieras le fait de pouvoir visualiser directement les données de cette vue dans ton IDE (Netbeans, HeidiSQL, MySQL workbench, et même phpMyAdmin permettent de voir les vues comme si elles étaient des tables, ce qui peut être pratique pour comprendre ce qui se passe dans ton modèle de données). Si ta fonction a des sous-requêtes, tente de passer par une vue avec des jointures: tu auras sans doute de bien meilleures perfs.
Note que dans ton cas, peut-être, une colonne virtuelle pourrait aussi être une solution: les colonnes virtuelles ont la possibilité d'être stockées pour ne pas être ré-évaluée constamment, donc, si ta fonction renvoie des résultat constants dans le temps (sauf si un joueur fait une action) et si cette colonne est plus souvent lue "qu'écrite", alors la colonne virtuelle sera une bonne solution (attention à ce que ton hébergeur le prenne bien en charge).
ce n'est pas l'usage d'une procédure. Une procédure effectue un traitement, et retournera 0, 1 ou plusieurs "resultsets". Il ne fait donc pas sens de mettre la procédure dans un SELECT.
Comme tu l'as découvert, il existe d'autres moyens de faire ce que tu souhaites:
1) L'usage d'une fonction
Ce principe est simple à mettre en place, et consiste à créer "un truc" similaire à une procédure, mais qui ne renverra non pas 0, 1 ou plusieurs resultsets mais uniquement 1 seule valeur scalaire. Tu peux alors utiliser cette fonction partout où une valeur scalaire peut apparaitre, à condition de passer à cette fonction les paramètres dont elle a besoin. Tu peux donc faire un SELECT myFunction(1234, t.x, t.y) FROM table AS t, ce qui aura pour effet de prendre toutes les lignes de la table, de calculer myFunction(...) pour chaque ligne, et de retourner la liste de ces résultats (sous la forme d'un resultset). Tu peux également l'utiliser dans un WHERE, façon SELECT * FROM table AS t WHERE myFunction(1234, t.x, t.y) = 2. Attention dans ce cas aux performances, car l'utilisation d'un index ne sera pas possible (sauf en passant par les colonnes virtuelles du dernier MySQL, éventuellement)
2) L'usage d'une vue
C'est très très similaire comme résultat, mais complètement différent comme façon de penser: une vue est simplement une table SQL, qui n'est pas stockée sur le serveur (en tous cas, pas chez MySQL, Oracle a une notion de "vues stockées", identique au système de vue à la seule différence que le SGBD se permet de stocker la vue sur le disque s'il estime que ce sera plus rapide), et qui est donc calculée à la volée, lors de la requête. Elle se présente comme donc comme une table, dont le contenu est le résultat d'un SELECT.... Par exemple, tu peux créer la vue myView correspondant à la requête SELECT (t.x+t.y)/1234 FROM table AS t. Faire un SELECT sur cette vue sera alors comme faire le SELECT correspondant à cette vue (ie: SELECT * FROM myView revient à faire SELECT (t.x+t.y)/1234 FROM table AS t ).
Du coup, les deux cas répondent à deux besoins différents:
• La fonction est pratique si le traitement est complexe, et utilisé dans des contextes totalement différents (par exemple, si le "1234" n'est pas constant, mais dépend d'autre choses). Par exemple, une fonction distance2d(x,y) retournant RETURN SQRT(x*x+y*y) est une bonne utilisation des fonctions, si celle-ci est réutilisée un peu partout dans différentes tables. C'est aussi utilisable (je crois, à vérifier en pratique) s'il y a des sous-requêtes à faire dans ladite fonction (mais là, les perfs, ouch, ça peut faire mal: tu verras à l'usage)
• La vue est pratique si le traitement est simple et n'est pas réutilisé dans d'autres contextes. Par exemple, SELECT *, (c.x*c.x + c.y*c.y) AS dist2d FROM mapcases AS c est une vue parfaitement acceptable. Note que la vue peut elle-même se servir de la fonction (SELECT *, distance2d(c.x, c.y) AS dist2d FROM mapcases).
Dans ton cas, je pense que la vue pourrait être plus adaptée: je doute que tu réutilises ta fonction ailleurs qu'ici, et je pense que tu apprécieras le fait de pouvoir visualiser directement les données de cette vue dans ton IDE (Netbeans, HeidiSQL, MySQL workbench, et même phpMyAdmin permettent de voir les vues comme si elles étaient des tables, ce qui peut être pratique pour comprendre ce qui se passe dans ton modèle de données). Si ta fonction a des sous-requêtes, tente de passer par une vue avec des jointures: tu auras sans doute de bien meilleures perfs.
Note que dans ton cas, peut-être, une colonne virtuelle pourrait aussi être une solution: les colonnes virtuelles ont la possibilité d'être stockées pour ne pas être ré-évaluée constamment, donc, si ta fonction renvoie des résultat constants dans le temps (sauf si un joueur fait une action) et si cette colonne est plus souvent lue "qu'écrite", alors la colonne virtuelle sera une bonne solution (attention à ce que ton hébergeur le prenne bien en charge).