USE `vn`; DROP procedure IF EXISTS `zone_getOptionsForShipment`; DELIMITER $$ USE `vn`$$ CREATE DEFINER=`root`@`%` PROCEDURE `zone_getOptionsForShipment`(vShipped DATE) BEGIN /** * Gets computed options for the passed zones and shipping date. * * @table tmp.zones(id) The zones ids * @param vShipped The shipping date * @return tmp.zoneOption(zoneFk, hour, travelingDays, price, bonus, specificity) The computed options */ DROP TEMPORARY TABLE IF EXISTS tLandings; CREATE TEMPORARY TABLE tLandings (INDEX (eventFk)) ENGINE = MEMORY SELECT e.id eventFk, @travelingDays := IFNULL(e.travelingDays, z.travelingDays) travelingDays, TIMESTAMPADD(DAY, @travelingDays, vShipped) landed FROM tmp.zone t JOIN zone z ON z.id = t.id JOIN zoneEvent e ON e.zoneFk = t.id; DROP TEMPORARY TABLE IF EXISTS tTemp; CREATE TEMPORARY TABLE tTemp ENGINE = MEMORY SELECT t.id zoneFk, IFNULL(TIME(e.`hour`), TIME(z.`hour`)) `hour`, IFNULL(e.price, z.price) price, IFNULL(e.bonus, z.bonus) bonus, CASE WHEN e.`type` = 'day' THEN 1 WHEN e.`type` = 'range' THEN 2 ELSE 3 END specificity, l.travelingDays, l.landed FROM tmp.zone t JOIN zone z ON z.id = t.id JOIN zoneEvent e ON e.zoneFk = t.id JOIN tLandings l ON l.eventFk = e.id WHERE ( e.`type` = 'day' AND e.`dated` = l.landed ) OR ( e.`type` != 'day' AND e.weekDays & (1 << WEEKDAY(l.landed)) AND (e.`started` IS NULL OR l.landed >= e.`started`) AND (e.`ended` IS NULL OR l.landed <= e.`ended`) ); DELETE t FROM tTemp t JOIN zoneExclusion e ON e.zoneFk = t.zoneFk AND e.`dated` = t.landed; DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption; CREATE TEMPORARY TABLE tmp.zoneOption ENGINE = MEMORY SELECT * FROM ( SELECT * FROM tTemp ORDER BY zoneFk, specificity ) t GROUP BY zoneFk; DROP TEMPORARY TABLE tTemp, tLandings; END$$ DELIMITER ;