Rom*_*kar 8 sql sql-server date-range intervals sql-server-2016
我需要存储简单的数据 - 假设我有一些产品将代码作为主键,一些属性和有效范围.所以数据可能如下所示:
Products
code value begin_date end_date
10905 13 2005-01-01 2016-12-31
10905 11 2017-01-01 null
Run Code Online (Sandbox Code Playgroud)
这些范围不重叠,所以在每个日期我都有一系列独特的产品及其属性.所以为了简化它的使用,我创建了这个函数:
create function dbo.f_Products
(
@date date
)
returns table
as
return (
select
from dbo.Products as p
where
@date >= p.begin_date and
@date <= p.end_date
)
Run Code Online (Sandbox Code Playgroud)
这就是我要用它的方式:
select
*
from <some table with product codes> as t
left join dbo.f_Products(@date) as p on
p.code = t.product_code
Run Code Online (Sandbox Code Playgroud)
这一切都很好,但我怎么能让优化器知道那些行是唯一的,有更好的执行计划?
我做了一些谷歌搜索,发现了一些非常好的DDL文章,可以防止在表格中存储重叠范围:
但即使我尝试这些约束,我也看到优化器无法理解结果记录集将返回唯一代码.
我想要的是某种方法,它给了我基本相同的性能,就像我在某个日期存储这些产品列表并选择它一样date = @date.
我知道一些RDMBS(如PostgreSQL)具有特殊的数据类型(Range Types).但是SQL Server没有这样的东西.
我错过了什么,或者在SQL Server中没有办法正确地做到这一点?
一个没有间隙的解决方案可能是这样的:
DECLARE @tbl TABLE(ID INT IDENTITY,[start_date] DATE);
INSERT INTO @tbl VALUES({d'2016-10-01'}),({d'2016-09-01'}),({d'2016-08-01'}),({d'2016-07-01'}),({d'2016-06-01'});
SELECT * FROM @tbl;
DECLARE @DateFilter DATE={d'2016-08-13'};
SELECT TOP 1 *
FROM @tbl
WHERE [start_date]<=@DateFilter
ORDER BY [start_date] DESC
Run Code Online (Sandbox Code Playgroud)
重要提示:确保有一个(唯一的)索引start_date
DECLARE @tbl TABLE(ID INT IDENTITY,ProductID INT,[start_date] DATE);
INSERT INTO @tbl VALUES
--product 1
(1,{d'2016-10-01'}),(1,{d'2016-09-01'}),(1,{d'2016-08-01'}),(1,{d'2016-07-01'}),(1,{d'2016-06-01'})
--product 1
,(2,{d'2016-10-17'}),(2,{d'2016-09-16'}),(2,{d'2016-08-15'}),(2,{d'2016-07-10'}),(2,{d'2016-06-11'});
DECLARE @DateFilter DATE={d'2016-08-13'};
WITH PartitionedCount AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY [start_date] DESC) AS Nr
,*
FROM @tbl
WHERE [start_date]<=@DateFilter
)
SELECT *
FROM PartitionedCount
WHERE Nr=1
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
969 次 |
| 最近记录: |