web-dev-qa-db-fra.com

Variables de procédure stockée MySQL à partir d'instructions SELECT

J'essaie de créer une procédure stockée. Voici ce que j'ai jusqu'à présent (ne fonctionne pas):

DELIMITER |
CREATE PROCEDURE getNearestCities(IN cityID INT)
    BEGIN
        DECLARE cityLat FLOAT;
        DECLARE cityLng FLOAT;
        SET cityLat = SELECT cities.lat FROM cities WHERE cities.id = cityID;
        SET cityLng = SELECT cities.lng FROM cities WHERE cities.id = cityID;
        SELECT *, HAVERSINE(cityLat,cityLng, cities.lat, cities.lng) AS dist FROM cities ORDER BY dist LIMIT 10;
    END |

HAVERSINE est une fonction que j'ai créée qui fonctionne très bien. Comme vous pouvez le voir, j'essaie de prendre l'id d'une ville dans le tableau des villes, puis de définir cityLat et cityLng sur d'autres valeurs de cet enregistrement. Je fais évidemment cela mal ici en utilisant SELECTs.

Est-ce seulement possible. Il semble que ce devrait être le cas. Toute aide que ce soit sera grandement appréciée.

12
Matt Harrison

Correction de quelques éléments et ajout d'une sélection alternative - supprimer le cas échéant.

DELIMITER |

CREATE PROCEDURE getNearestCities
(
IN p_cityID INT -- should this be int unsigned ?
)
BEGIN

DECLARE cityLat FLOAT; -- should these be decimals ?
DECLARE cityLng FLOAT;

    -- method 1
    SELECT lat,lng into cityLat, cityLng FROM cities WHERE cities.cityID = p_cityID;

    SELECT 
     b.*, 
     HAVERSINE(cityLat,cityLng, b.lat, b.lng) AS dist 
    FROM 
     cities b 
    ORDER BY 
     dist 
    LIMIT 10;

    -- method 2
    SELECT   
      b.*, 
      HAVERSINE(a.lat, a.lng, b.lat, b.lng) AS dist
    FROM     
      cities AS a
    JOIN cities AS b on a.cityID = p_cityID
    ORDER BY 
      dist
    LIMIT 10;

END |

delimiter ;
16
Jon Black

Il vous suffit de mettre vos instructions SELECT entre parenthèses pour indiquer qu'il s'agit de sous-requêtes:

SET cityLat = (SELECT cities.lat FROM cities WHERE cities.id = cityID);

Alternativement, vous pouvez utiliser la syntaxe SELECT ... INTO de MySQL. Un avantage de cette approche est que cityLat et cityLng peuvent être attribués à partir d'un seul accès à la table:

SELECT lat, lng INTO cityLat, cityLng FROM cities WHERE id = cityID;

Cependant, la procédure entière peut être remplacée par une seule instruction SELECT auto-jointe:

SELECT   b.*, HAVERSINE(a.lat, a.lng, b.lat, b.lng) AS dist
FROM     cities AS a, cities AS b
WHERE    a.id = cityID
ORDER BY dist
LIMIT    10;
15
eggyal