1
votes

La date d'incrémentation de la boucle de procédure stockée MySQL dans la requête de sélection renvoie la dernière date

J'ai une procédure stockée qui incrémente une date spécifique dans une requête de sélection. J'ai besoin d'obtenir la valeur actuelle de la variable de date incrémentielle avec d'autres champs. Mais la requête renvoie toujours la dernière date incrémentée uniquement. Pouvez-vous s'il vous plaît me montrer où se trouve l'erreur?.

Procédure stockée:

BEGIN
DECLARE nextDate DATE;
SET nextDate = firstStayDate;
WHILE nextDate <= lastStayDate DO
SELECT nextDate as stayDate, Room_type, SUM(No_of_room), ArrivalDate, DepartDate, state FROM reservation_temp WHERE Reservation_is_done = 1 AND state != 0 AND ArrivalDate <= nextDate AND DepartDate > nextDate GROUP BY stayDate, Room_type;
SET nextDate = DATE_ADD(nextDate, INTERVAL 1 DAY);
END WHILE;

Le résultat est généré lorsqu'il est appelé call IBE_getAvailabilityForRange ('2019-02-25' , '2019-02-27');

[EDIT] J'en ai besoin pour produire les résultats pour 2019-02-25, 2019-02-26, 2019-02-27. Actuellement, il ne me donne les résultats que pour le 27/02/2019.

[EDIT: Procédure stockée modifiée avec GROUP by et SUM]

CREATE PROCEDURE `IBE_getAvailabilityForRange`(IN firstStayDate DATE, IN lastStayDate DATE)
BEGIN
DECLARE nextDate DATE;
SET nextDate = firstStayDate;
WHILE nextDate <= lastStayDate DO
SELECT nextDate as stayDate, Room_type, No_of_room, ArrivalDate, DepartDate, state FROM reservation_temp WHERE Reservation_is_done = 1 AND state != 0 AND ArrivalDate <= nextDate AND DepartDate > nextDate;
SET nextDate = DATE_ADD(nextDate, INTERVAL 1 DAY);
END WHILE;
END


7 commentaires

Il semble en fait que vous ne voyez que les résultats de la dernière itération de la boucle WHILE car tous ces résultats sont des résultats valides pour nextDate = '2019- 02-27 '. Cela ressemble à un problème dans la manière dont vous récupérez les résultats de la procédure stockée.


@nick, ça devrait être le cas. Pouvez-vous me montrer comment obtenir les résultats pour d'autres dates également.


Quels sont vos résultats souhaités? Le problème est causé par l'instruction SELECT itérant sur l'ensemble de lignes du jour, avant l'incrémentation de nextDate . En conséquence, votre procédure exécutera plusieurs instructions SELECT pour chaque jour, affichant la dernière exécutée dans votre outil de requête. Sans savoir comment vous voulez les résultats, nous ne pouvons pas vraiment proposer une solution appropriée. c'est-à-dire afficher les enregistrements en double pour chaque stayDate qui correspondent aux critères ( UNION ), une seule ligne pour chaque stayDate ou filtrer les doublons d'une manière ou d'une autre.


@Johna exécutez-vous la requête directement dans MySQL Workbench ou phpMyAdmin ou depuis un framework d'application? Dans ce dernier cas, vous devez ajouter votre code à la question.


@fyrye J'ai modifié la procédure stockée, veuillez vérifier. Je dois obtenir Room_type et la somme de No_of_room par jour.


Je commencerais par une vue d'ensemble. Voir meta.stackoverflow.com/questions/333952/...


Je me demande également à quelle question cette requête tente de répondre


3 Réponses :


0
votes

Je vous recommande de ne pas gonfler une simple requête avec une procédure stockée:

Si vous bouclez dans une procédure stockée sur quelque chose, une requête pourrait faire son très inefficace.

Donc, cette procédure pourrait être remplacé par une seule requête:

SELECT Room_type, No_of_room, ArrivalDate, DepartDate, state
FROM reservation_temp
WHERE Reservation_is_done = 1
      AND state != 0
      AND ArrivalDate <= {arrivedate}
      AND {enddate} < DepartDate

reservation_temp est-il vraiment une table temporaire?


2 commentaires

En fait, reservation_temp n'est pas une table temporaire. C'est ainsi que les développeurs ont nommé la table.


Wow, c'est juste demander à une personne de le laisser tomber.



2
votes

Comme mentionné dans mon commentaire, le problème est causé par l'instruction SELECT itérant sur l'ensemble de lignes pour la journée, avant d'incrémenter nextDate . En conséquence, votre procédure exécutera plusieurs instructions SELECT pour chaque jour, et retournera le résultat de la dernière requête exécutée.

ie:

/* CALL IBE_getAvailabilityForRange('2019-01-01', '2019-01-05'); */

tmp_stays
---
| stayDate | Room_type | rooms | ArrivalDate | DepartDate | state | 
| --- | ---: | ---: | --- | --- | ---: | 
| 2019-01-01 | 1 | 2 | 2019-01-01 | 2019-01-03 | 1 | 
| 2019-01-02 | 1 | 1 | 2019-01-01 | 2019-01-03 | 1 | 
| 2019-01-03 | 1 | 1 | 2019-01-03 | 2019-01-04 | 1 | 
| 2019-01-04 | 1 | 1 | 2019-01-04 | 2019-01-05 | 1 | 

Pour résoudre le problème de la manière que je pense que vous cherchez à atteindre, une méthode consiste à utiliser une table temporaire pour stocker les enregistrements récupérés pour chaque jour jusqu'à ce que chaque jour soit traité, puis à récupérer les valeurs de la table temporaire. P >

Cependant, vous devez mieux définir vos colonnes GROUP BY pour ArrivalDate, DepartDate et state. Comme MySQL 5.7+ a ONLY_FULL_GROUP_BY activé par défaut et provoquera une erreur. J'ai utilisé MIN , MAX et ajouté state aux regroupements pour éviter les erreurs.

Vous pouvez également utiliser explicitement ANY_VALUE () sur les colonnes, pour permettre à MySQL de choisir une valeur dans chaque groupe qui n'a pas été agrégée. [sic]

reservation_temp
---
| id | Room_type | state | No_of_room | ArrivalDate | DepartDate | Reservation_is_done | 
| ---: | ---: | ---: | ---: | --- | --- | ---: | 
| 1 | 1 | 1 | 1 | 2019-01-01 | 2019-01-02 | 1 | 
| 2 | 1 | 1 | 1 | 2019-01-01 | 2019-01-03 | 1 | 
| 3 | 1 | 1 | 1 | 2019-01-03 | 2019-01-04 | 1 | 
| 4 | 1 | 1 | 1 | 2019-01-04 | 2019-01-04 | 1 | 
| 5 | 1 | 1 | 1 | 2019-01-04 | 2019-01-05 | 1 | 

Avec l'ensemble de données de (notez que les id 1 et 2 ont des valeurs de DepartDate différentes)

CREATE PROCEDURE `IBE_getAvailabilityForRange`(IN firstStayDate DATE, IN lastStayDate DATE)
BEGIN
DECLARE nextDate DATE;

DROP TEMPORARY TABLE IF EXISTS tmp_stays;
CREATE TEMPORARY TABLE IF NOT EXISTS tmp_stays(
    stayDate DATE,
    Room_type INT(10),
    rooms INT(10),
    ArrivalDate DATE,
    DepartDate DATE,
    state INT
);

SET nextDate = firstStayDate;
WHILE nextDate <= lastStayDate DO
    INSERT tmp_stays
    SELECT
       nextDate, 
       Room_type, 
       SUM(No_of_room), 
       MIN(ArrivalDate), 
       MAX(DepartDate), 
       state
    FROM reservation_temp 
    WHERE Reservation_is_done = 1 
    AND state != 0 
    AND ArrivalDate <= nextDate 
    AND DepartDate > nextDate 
    GROUP BY nextDate, Room_type, state;

    SET nextDate = DATE_ADD(nextDate, INTERVAL 1 DAY);
END WHILE;

SELECT * FROM tmp_stays;
DROP TEMPORARY TABLE IF EXISTS tmp_stays;
END

Résultat

SELECT day1;
SELECT day2;


1 commentaires

Cette réponse résout le problème que j'ai décrit ici. Alors je l'ai accepté comme réponse. Cependant, j'ai trouvé une autre approche simple pour obtenir le résultat dont j'ai besoin.



0
votes

Vous voudrez peut-être consulter cette discussion: générer des jours à partir de la plage de dates

En utilisant certaines requêtes de la discussion, vous pouvez obtenir une liste de dates de votre plage de dates. Ensuite, juste à l'intérieur / à gauche, joignez vos données et vous obtenez ce que vous voulez.

Avec mon implémentation (j'ai une table d'aide + vue, mais ce n'est pas obligatoire), la requête résultante ressemblerait à ceci:

SELECT
      Dates.d
    , reservation_temp.*
FROM
    global.Dates
    INNER JOIN reservation_temp ON (
            Reservation_is_done = 1
        AND state != 0
        AND ArrivalDate <= Dates.d
        AND DepartDate > Dates.d
    )
WHERE
    Dates.d BETWEEN firstStayDate AND lastStayDate


0 commentaires