高效的WHERE子句来检查BETWEEN minumim和NULL

时间:2018-02-01 17:32:54

标签: sql sql-server tsql

我有一个SQL查询,它根据租借期限返回价格水平。该表有列:

ProductID (UNIQUEIDENTIFIER), MinDuration(INT), MaxDuration(INT), Price (DECIMAL(10, 4)

我目前使用的查询的简化版本是:

SELECT Price
FROM RentalPrices
WHERE ProductID = @ProductID
  AND @Duration BETWEEN MinDuration AND MaxDuration;

表格示例

+--------------------------------------+-------------+-------------+-------+
|              ProductID               | MinDuration | MaxDuration | Price |
+--------------------------------------+-------------+-------------+-------+
| e93d19e1-142f-41cc-8f39-9cf7607717ac |           0 | 3           |    25 |
| e93d19e1-142f-41cc-8f39-9cf7607717ac |           4 | 7           |    50 |
| e93d19e1-142f-41cc-8f39-9cf7607717ac |           8 | 14          |   100 |
| e93d19e1-142f-41cc-8f39-9cf7607717ac |          15 | 30          |   200 |
| e93d19e1-142f-41cc-8f39-9cf7607717ac |          31 | NULL        |   500 |
+--------------------------------------+-------------+-------------+-------+

我的问题是大于或等于31的值不会找到最后一行,即开放式最大值,是否有一个好的,简单的方法来处理它?我知道一些可能有用的选项,但我不确定什么是最好的。

  • BETWEEN MinDuration AND ISNULL(MaxDuration,2147483647)
  • @Duration >= MinDuration AND (@Duration <= MaxDuration OR MaxDuration IS NULL)

特别是目标是效率超过最大数量的情况,我们最终达到最后一个价值的情况很少见(在实际表格中它不是一个月,但可能是六个月以上的任何一个月) ,取决于正在租用的产品),因此最有效的解决方案是在两个值之间的持续时间,同时仍然处理上限为空,效率良好的情况,是目标。

2 个答案:

答案 0 :(得分:4)

最有效的方法可能是忽略maxduration

SELECT TOP (1) Price
FROM ?
WHERE ProductID = @ProductID AND MinDuration <= @Duration
ORDER BY MinDuration DESC;

这可以使用(ProductId, MinDuration)上的索引。

至于你的问题本身。我会投票支持在表格中存储最大值,而不是为此目的使用NULL。不是最美观的解决方案,但它简化了编码。你提出的两种方法之间的选择实际上是关于美学(虽然我会使用ANSI标准COALESCE())。

答案 1 :(得分:3)

效率不高但我觉得很干净

SELECT Price
FROM RentalPrices
WHERE ProductID = @ProductID
AND @Duration BETWEEN MinDuration AND isnull(MaxDuration, @Duration);

考虑ProductID上的群集PK,价格

declare @rental table (id int not null, minDuration int not null, maxDuration int, price int not null);
insert into @rental (id, minDuration, maxDuration, price) values 
         (1, 0, 3, 25)
       , (1, 4, 7, 50)  
       , (1, 8, 14, 100)
       , (1, 15, 30, 200)
       , (1, 31, null, 500);

declare @id int = 1;
declare @duration int = 15;

select id, minDuration, maxDuration, price 
  from @rental
 order by id, MinDuration;

SELECT Price, @duration, minDuration, maxDuration
  FROM @rental
 WHERE id = @id
   AND @duration BETWEEN minDuration AND isnull(maxDuration, @Duration)
 order by id, minDuration;