具有条件结果的复杂mysql查询

xkftehaa  于 2021-06-21  发布在  Mysql
关注(0)|答案(3)|浏览(499)

mysql数据库的下一个结构是:

boats
id    name
-------------
1     name1
2     name2

boat_prices
id boat_id       date       duration      price     is_default  
---------------------------------------------------------------
1     1       '2018-01-01'       1         100          
2     1       '2018-01-01'       2         200          
3     1          null          null        100           1
4     2       '2018-01-02'       2         400
5     2       '2018-01-02'       4         800
6     2          null          null        200           1
7     3       '2018-01-03'       5        1500
8     3          null          null        300           1

这些船有一个特定日期和持续时间的价格,以天为单位。所有船只都有一个默认的“起始”价格,由date=null和duration=null标识。但是,并不是所有的船都有价格。当我搜索特定日期和持续时间的船价时,查询应该返回包含该日期和持续时间的价格的所有行,如果船没有´t获取该日期的价格返回其“起始”默认价格。
示例:对于日期='2018-01-01,持续时间=1,结果应为:

boat_prices
id boat_id       date       duration      price       is_default
----------------------------------------------------------------
1     1       '2018-01-01'       1         100       
6     2          null          null        200           1
8     3          null          null        300           1

我做这个查询示例只是为了简化,但是请考虑到除此之外,查询还有一些与其他表的连接。
我需要你的帮助。

nwo49xxi

nwo49xxi1#

我相信rick的左路是对的,但你可能需要两个。一个得到船的价格,有资格的日期感兴趣,另一个明确的默认值。

select 
      b.id,
      b.name,
      DefPrice.price as DefaultPrice,
      Specials.price as SpecialsPrice,
      COALESCE( Specials.price, DefPrice.price ) as DiscountOrDefaultPrice
   from
      ( select @parmDate = '2018-01-01' ) sqlvars,
      boats b
         JOIN boat_prices DefPrice
            on b.id = DefPrice.boat_id
           AND DefPrice.date IS NULL
           AND DefPrice.Duration IS NULL
         LEFT JOIN boat_prices Specials
            on b.id = Specials.boat_id
           AND Specials.date <= @parmDate
           AND @parmDate <= Date_Add( Specials.Date, INTERVAL (Specials.duration -1 ) DAY )

现在,您可以通过执行coalesce()始终只返回一个有问题的价格,如果没有特殊价格,它将通过discountordefaultprice列获得默认值。
选择要运行的列的版本。这应该得到所有的船,不管一些特殊的价格为基础的持续时间。当您更改所讨论的参数日期时——即使您更改了当前日期,它也会工作。这是因为您正在测试的日期对所有可能的特殊船价格和其开始到开始+持续时间结束日期范围的问题。如果有多个价格与日期重叠,则只返回那些重叠的多行。
我把持续时间加起来等于减去1。例如,如果你的日期是2018-01-01,有效期为1天,这是否意味着只有这一天有效?或2018-01-02(含)之前。-1强制限定只有一天。所以2018-01-01一天的价格只有2018-01-01。
2018-01-02的另一个示例持续两天。给我,表示2天,包括01-02到01-03。实际两天。
日期和范围评论确认
我想我对你的数据需求的解释是错误的。你方提供的两份注明日期的船价记录样本显然不够。你说你想要所有的船,不管有没有特殊的价格记录。因此,您必须从boat和join开始,以获得所有可能的“默认”定价。只有左连接组件需要调整。
也就是说,让我们模拟更多的数据。假设你有以下

Boad ID    Date        Duration    Rate
1        2018-01-01       1        x
1        2018-01-02       4        y
2        2018-01-02       2        z
2        2018-01-04       4        a
3        2018-01-03       5        b

如果我提供日期2018-01-01,我应该查看哪些费率记录?如果我提供日期2018-01-03,什么记录?如果我提供日期2018-01-05,什么记录?

pepwfjgg

pepwfjgg2#

对于特定日期“2018-01-01”和期限1,我将使用如下工会条款:
(注:为“添加”编辑的是默认列)

-- Get prices for particular day and duration.
(SELECT
    boat_id,
    date,
    duration,
    price,
    0 AS is_default
FROM
    boat_prices
WHERE
    date = "2018-01-01" AND duration = 1)

UNION

-- Add defaults prices for those don't have a price on the particular day and duration
(SELECT
    boat_id,
    date,
    duration,
    price,
    is_default
FROM
    boat_prices
WHERE
    date IS NULL
AND 
    duration IS NULL
AND
    boat_id NOT IN (SELECT boat_id
                    FROM boat_prices
                    WHERE date ="2018-01-01" AND duration = 1))

存储过程解决方案示例

DELIMITER //
CREATE PROCEDURE GetPricesByDateAndDuration(IN pDate DATE, IN pDuration INT)
BEGIN

    -- Get prices for particular day and duration.

    (SELECT
        boat_id,
        date,
        duration,
        price,
        0 AS is_default
    FROM
        boat_prices
    WHERE
        date = pDate AND duration = pDuration)

    UNION

    -- Add defaults prices for those don't have a price on the particular day and duration

    (SELECT
        boat_id,
        date,
        duration,
        price,
        is_default
    FROM
        boat_prices
    WHERE
        date IS NULL
    AND 
        duration IS NULL
    AND
        boat_id NOT IN (SELECT boat_id
                        FROM boat_prices
                        WHERE date = pDate AND duration = pDuration))

END //
DELIMITER ;

然后你可以这样调用这个过程:

CALL GetPricesByDateAndDuration('2018-01-01', 1);
gzszwxb4

gzszwxb43#

不要考虑那种笨重的输出,考虑一下:

boat_id      price   default     
-----------------------------
   1          100
   2          300   (default)

像这样的事情应该会产生:

SELECT  boat_id,
        IF(b.price IS NULL, dflt.price, b.price) AS price,
        IF(b.price IS NULL, '(default)', '')  AS default
    FROM       boat_prices AS dflt
    LEFT JOIN  boat_prices AS b  USING(boat_id)
    WHERE  dflt.date IS NULL
      AND  dflt.duration IS NULL
      AND  '2018-01-01' >= b.date
      AND  '2018-01-01' <  b.date + INTERVAL b.duration DAY
    GROUP BY  boat_id

相关问题