3

次のような一連の期間があります。

CREATE TABLE `periods` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `start_at` date DEFAULT NULL,
  `end_at` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

LOCK TABLES `periods` WRITE;

INSERT INTO `periods` (`id`, `start_at`, `end_at`)
VALUES
    (1,'2013-04-29','2013-04-30'),
    (2,'2013-05-05','2013-05-10'),
    (3,'2013-05-10','2013-05-15'),
    (4,'2013-05-15','2013-05-16'),
    (5,'2013-05-18','2013-05-19'),
    (6,'2013-05-19','2013-05-25');

UNLOCK TABLES;

私の意図した欲求は、特定の期間が 1 つまたは複数の期間で完全にカバーされているかどうかを知るための最も最適化された方法です。

例えば:

1)からまでnullのリクエストを取得するには、 からまでの期間をカバーしません2013-04-292013-05-102013-04=302013-05-05

2) からの要求の期間 ID (または少なくともtrueまたは任意のコンテンツ)を取得2013-05-06する2013-05-15

2013-05-06更新: 主な目標は、指定された期間 (例 2 のように からまで2013-05-15) がレンタル可能かどうかを定義することです。データベースの期間はレンタル可能なシーズンですので、その日のいずれかがカバーされていない場合、滞在全体をレンタルすることはできません.

4

4 に答える 4

2

編集: MySQL が動作する SQL Fiddle については、こちらを参照してください: SQLFiddle、今回は実際に適切に動作します:-)

これらを試してみてください。肝心なのはShortfall > 0、レンタルを予約できないということです。

MSSQL - これが私が解決した方法です

DECLARE @start DATETIME = '2013-04-29' -- this will depend on your dateformat
DECLARE @end DATETIME = '2013-05-10'
DECLARE @days INT = DATEDIFF(D,@start, @end) -- this is how many days we actually want to stay
DECLARE @unusedDays INT = 0 -- this will be the number of unused days from the rental periods in which our start and end dates fall
SELECT  @UnusedDays = DATEDIFF(D,@end,end_at) FROM PERIODS WHERE (@end > start_at AND @end <= end_at) -- how many spare days are there in the final period?
SELECT  @UnusedDays = @UnusedDays + DATEDIFF(D,start_at, @start) FROM PERIODS WHERE (@start >= start_at AND @start < end_at) -- how many spare days are there in the start period?
SELECT  @days + @UnusedDays - SUM(DATEDIFF(D,start_at,end_at)) AS Shortfall, -- total shortfall in days. Zero if we are okay to rent
        SUM(DATEDIFF(D,start_at,end_at)) AS AvailableDays, -- total number of days available in all periods covering our chosen rental period
        @days AS DesiredDays, -- number of days we want to rent
        @UnusedDays AS WastedDays -- number of wasted days (if we start or end our rental mid-period)
FROM    PERIODS 
WHERE   (@start >= start_at AND @start < end_at) -- period in which our selected rental starts
OR      (end_at < @end AND start_at > @start) -- period completely within our selected rental
OR      (@end > start_at AND @end <= end_at) -- period in which our selected rental ends

これにより、次のような出力が得られます。

-- if you have @start = '2013-05-05'
-- and @end = '2013-05-13'
-- then you get
Shortfall AvailableDays DesiredDays WastedDays

0---------10------------8-----------2---------

-- if you have @start = '2013-04-29'
-- and @end = '2013-05-10'
-- then you get
Shortfall AvailableDays DesiredDays WastedDays

5---------6-------------11----------0---------

MySQL - これは実際に必要なものです

SET @start = '2013-04-29';
SET @end = '2013-05-10';
SET @days = DATEDIFF(@end, @start); -- this is how many days we actually want to stay
SET @UnusedDays = 0; -- this will be the number of unused days from the rental periods in which our start and end dates fall
SELECT  @UnusedDays := DATEDIFF(end_at,@end) FROM PERIODS WHERE (@end > start_at AND @end <= end_at); -- how many spare days are there in the final period?
SELECT 'hello';
SELECT  @UnusedDays := @UnusedDays + DATEDIFF(@start, start_at) FROM PERIODS WHERE (@start >= start_at AND @start < end_at); -- how many spare days are there in the start period?
SELECT 'hello';
SELECT  @days + @UnusedDays - SUM(DATEDIFF(end_at, start_at)) AS Shortfall, -- total shortfall in days. Zero if we are okay to rent
        SUM(DATEDIFF(end_at, start_at)) AS AvailableDays, -- total number of days available in all periods covering our chosen rental period
        @days AS DesiredDays, -- number of days we want to rent
        @UnusedDays AS WastedDays -- number of wasted days (if we start or end our rental mid-period)
FROM    PERIODS 
WHERE   (@start >= start_at AND @start < end_at) -- period in which our selected rental starts
OR      (end_at < @end AND start_at > @start) -- period completely within our selected rental
OR      (@end > start_at AND @end <= end_at); -- period in which our selected rental ends
于 2013-04-29T18:07:24.690 に答える
1

@Dommer のアプローチとそこに含まれる詳細が気に入っていますが (ありがとうございます)、IRC#mysql で @snoyes によって提供されたアプローチを好みます。

SELECT IF(COUNT(*), false, true) AS rentable
FROM(
  SELECT
    a.end_at AS START,
    Min(b.start_at) AS END
  FROM periods AS a
  JOIN periods AS b ON a.end_at <= b.start_at
  GROUP BY a.end_at
  HAVING a.end_at < MIN(b.start_at)
) AS gaps
WHERE
  gaps.START < '2013-05-17' AND gaps.END > '2013-05-05';

動作するSQLFiddleも利用できます。

詳細については、最初の参照元はhttp://www.artfulsoftware.com/infotree/qrytip.php?id=577です。

于 2013-05-03T10:46:50.057 に答える