SQL-查找列日期是否至少部分包含日期范围
我需要创建一个报告,我正在努力使用SQL脚本。 我要查询的表是一个公司\状态\历史记录表,其中包含如下条目(我无法理解的条目) 表公司状况历史 栏目:SQL-查找列日期是否至少部分包含日期范围,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我需要创建一个报告,我正在努力使用SQL脚本。 我要查询的表是一个公司\状态\历史记录表,其中包含如下条目(我无法理解的条目) 表公司状况历史 栏目: | id | company_id | status_id | effective_date | 数据: 我想回答以下问题:“获取所有在2017年1月1日至2017年12月31日期间至少处于状态1的公司” 以上是我不知道如何处理的情况,因为我需要添加一些类型的逻辑: “如果此行状态为1且其日期在日期范围之前,请检查下一行的日期是否在日期范围内
| id | company_id | status_id | effective_date |
数据:
我想回答以下问题:“获取所有在2017年1月1日至2017年12月31日期间至少处于状态1的公司”
以上是我不知道如何处理的情况,因为我需要添加一些类型的逻辑:
- “如果此行状态为1且其日期在日期范围之前,请检查下一行的日期是否在日期范围内。”
- “如果此行的状态为1,且其日期在日期范围之后,请在该行之前检查其日期是否在日期范围之内。”
- 如果您希望查找在任何时刻处于状态1且在请求的时间段内有记录的id:
- 您希望在状态1和期间内查找id的情况:
- 如果您希望查找在任何时刻处于状态1且在请求的时间段内有记录的id:
- 您希望在状态1和期间内查找id的情况:
- 试试这个,不言自明。回答您问题的这一部分:
我想回答一个问题:“让所有的公司都参与进来。”
2017年1月1日期间状态1中的某个点的最小值-
2017年12月31日”
试试这个,不言自明。回答您问题的这一部分: 我想回答一个问题:“让所有的公司都参与进来。” 2017年1月1日期间状态1中的某个点的最小值- 2017年12月31日”
也许这就是你要找的?对于这类问题,您需要连接表的两个实例,在本例中,我只是通过Id连接下一个记录,这可能并不完全正确。为了做得更好,您可以使用一个窗口函数(如row_number)创建一个新Id,并根据您的需求标准对表进行排序 如果此行状态为1且其日期在日期范围检查之前 如果下一行的日期在日期范围内,则显示下一行
declare@range\u st date='2017-01-01'
声明日期为“2017-12-31”
挑选
案例
当csh1.status\u id=1和csh1.effective\u date时,可能这就是您要找的?对于这类问题,您需要连接表的两个实例,在本例中,我只是通过Id连接下一个记录,这可能并不完全正确。为了做得更好,您可以使用一个窗口函数(如row_number)创建一个新Id,并根据您的需求标准对表进行排序
如果此行状态为1且其日期在日期范围检查之前
如果下一行的日期在日期范围内,则显示下一行
declare@range\u st date='2017-01-01'
声明日期为“2017-12-31”
挑选
案例
当csh1.status\u id=1和csh1.effective\u date时,我建议使用cte和窗口函数行号。有了它,您可以找到所需的记录。例如:
DECLARE @t TABLE(
id INT
,company_id INT
,status_id INT
,effective_date DATETIME
)
INSERT INTO @t VALUES
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
DECLARE @StartDate DATETIME = '2017-01-01';
DECLARE @EndDate DATETIME = '2017-12-31';
WITH cte AS(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) AS rn
FROM @t
),
cteLeadLag AS(
SELECT c.*, ISNULL(c2.effective_date, c.effective_date) LagEffective, ISNULL(c3.effective_date, c.effective_date)LeadEffective
FROM cte c
LEFT JOIN cte c2 ON c2.company_id = c.company_id AND c2.rn = c.rn-1
LEFT JOIN cte c3 ON c3.company_id = c.company_id AND c3.rn = c.rn+1
)
SELECT 'Included' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Following' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date > @EndDate
AND LagEffective BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Trailing' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date < @EndDate
AND LeadEffective BETWEEN @StartDate AND @EndDate
DECLARE@t表(
id INT
,company_id INT
,status_id INT
,生效日期日期时间
)
插入到@t值中
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
声明@StartDate DATETIME='2017-01-01';
声明@EndDate DATETIME='2017-12-31';
以cte为例(
挑选*
,第()行(按公司id顺序按生效日期划分)为rn
来自@t
),
cteLeadLag AS(
选择c.*,ISNULL(c2.生效日期,c.生效日期)LagEffect,ISNULL(c3.生效日期,c.生效日期)LeadEffect
来自cte c
在c2.company_id=c.company_id和c2.rn=c.rn-1上左连接cte c2
在c3.company_id=c.company_id和c3.rn=c.rn+1上左连接cte c3
)
选择“包含”作为范围状态*
来自cteLeadLag
其中status_id=1
以及@StartDate和@EndDate之间的生效日期
联合所有
选择“以下”作为范围状态*
来自cteLeadLag
其中status_id=1
和生效日期>@EndDate
并且在@StartDate和@EndDate之间有效
联合所有
选择“跟踪”作为范围状态*
来自cteLeadLag
其中status_id=1
和生效日期<@EndDate
在@StartDate和@EndDate之间生效
我首先选择所有记录及其领先和滞后日期,然后在所需的时间跨度内对其进行检查。我建议使用cte和窗口功能行号。有了它,您可以找到所需的记录。例如:
DECLARE @t TABLE(
id INT
,company_id INT
,status_id INT
,effective_date DATETIME
)
INSERT INTO @t VALUES
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
DECLARE @StartDate DATETIME = '2017-01-01';
DECLARE @EndDate DATETIME = '2017-12-31';
WITH cte AS(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) AS rn
FROM @t
),
cteLeadLag AS(
SELECT c.*, ISNULL(c2.effective_date, c.effective_date) LagEffective, ISNULL(c3.effective_date, c.effective_date)LeadEffective
FROM cte c
LEFT JOIN cte c2 ON c2.company_id = c.company_id AND c2.rn = c.rn-1
LEFT JOIN cte c3 ON c3.company_id = c.company_id AND c3.rn = c.rn+1
)
SELECT 'Included' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Following' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date > @EndDate
AND LagEffective BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Trailing' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date < @EndDate
AND LeadEffective BETWEEN @StartDate AND @EndDate
DECLARE@t表(
id INT
,company_id INT
,status_id INT
,生效日期日期时间
)
插入到@t值中
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
声明@StartDate DATETIME='2017-01-01';
声明@EndDate DATETIME='2017-12-31';
以cte为例(
挑选*
,第()行(按公司id顺序按生效日期划分)为rn
来自@t
),
cteLeadLag AS(
选择c.*,ISNULL(c2.生效日期,c.生效日期)LagEffect,ISNULL(c3.生效日期,c.生效日期)LeadEffect
来自cte c
在c2.company_id=c.company_id和c2.rn=c.rn-1上左连接cte c2
在c3.company_id=c.company_id和c3.rn=c.rn+1上左连接cte c3
)
选择“包含”作为范围状态*
来自cteLeadLag
其中status_id=1
以及@StartDate和@EndDate之间的生效日期
联合所有
选择“以下”作为范围状态*
来自cteLeadLag
其中status_id=1
和生效日期>@EndDate
并且在@StartDate和@EndDate之间有效
联合所有
选择“跟踪”作为范围状态*
来自cteLeadLag
其中status_id=1
和生效日期<@EndDate
在@StartDate和@EndDate之间生效
我首先选择所有记录及其前导和la
SELECT *
FROM company_status_history
WHERE status_id=1
AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
declare @range_st date = '2017-01-01'
declare @range_en date = '2017-12-31'
select
case
when csh1.status_id=1 and csh1.effective_date<@range_st
then
case
when csh2.effective_date between @range_st and @range_en then true
else false
end
else NULL
end
from company_status_history csh1
left join company_status_history csh2
on csh1.id=csh2.id+1
declare @range_st date = '2017-01-01'
declare @range_en date = '2017-12-31'
select
case
when csh1.status_id=1 and csh1.effective_date<@range_st
then
case
when csh2.effective_date between @range_st and @range_en then true
else false
end
when csh1.status_id=1 and csh1.effective_date>@range_en
then
case
when csh3.effective_date between @range_st and @range_en then true
else false
end
else null -- ¿?
end
from company_status_history csh1
left join company_status_history csh2
on csh1.id=csh2.id+1
left join company_status_history csh3
on csh1.id=csh3.id-1
DECLARE @t TABLE(
id INT
,company_id INT
,status_id INT
,effective_date DATETIME
)
INSERT INTO @t VALUES
(1, 10, 1, '2016-12-30 00:00:00.000')
,(2, 10, 5, '2017-02-04 00:00:00.000')
,(3, 11, 5, '2017-06-05 00:00:00.000')
,(4, 11, 1, '2018-04-30 00:00:00.000')
DECLARE @StartDate DATETIME = '2017-01-01';
DECLARE @EndDate DATETIME = '2017-12-31';
WITH cte AS(
SELECT *
,ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) AS rn
FROM @t
),
cteLeadLag AS(
SELECT c.*, ISNULL(c2.effective_date, c.effective_date) LagEffective, ISNULL(c3.effective_date, c.effective_date)LeadEffective
FROM cte c
LEFT JOIN cte c2 ON c2.company_id = c.company_id AND c2.rn = c.rn-1
LEFT JOIN cte c3 ON c3.company_id = c.company_id AND c3.rn = c.rn+1
)
SELECT 'Included' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Following' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date > @EndDate
AND LagEffective BETWEEN @StartDate AND @EndDate
UNION ALL
SELECT 'Trailing' AS RangeStatus, *
FROM cteLeadLag
WHERE status_id = 1
AND effective_date < @EndDate
AND LeadEffective BETWEEN @StartDate AND @EndDate
id company_id status_id effective_date
-------------------------------------------
1 10 1 2016-12-15
2 10 1 2016-12-30
3 10 5 2017-02-04
4 10 4 2017-02-08
5 11 5 2017-06-05
6 11 1 2018-04-30
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
ORDER BY company_id, effective_date
id company_id status_id effective_date grp
-----------------------------------------------
1 10 1 2016-12-15 0
2 10 1 2016-12-30 1
3 10 5 2017-02-04 2
4 10 4 2017-02-08 2
5 11 5 2017-06-05 0
6 11 1 2018-04-30 0
;WITH CTE AS
(
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
)
SELECT id, company_id, status_id, effective_date,
ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) -
cnt AS grp
FROM CTE
id company_id status_id effective_date grp
-----------------------------------------------
1 10 1 2016-12-15 1
2 10 1 2016-12-30 1
3 10 5 2017-02-04 1
4 10 4 2017-02-08 2
5 11 5 2017-06-05 1
6 11 1 2018-04-30 2
;WITH CTE AS
(
SELECT t.id, t.company_id, t.status_id, t.effective_date, x.cnt
FROM company_status_history AS t
OUTER APPLY
(
SELECT COUNT(*) AS cnt
FROM company_status_history AS c
WHERE c.status_id = 1
AND c.company_id = t.company_id
AND c.effective_date < t.effective_date
) AS x
), CTE2 AS
(
SELECT id, company_id, status_id, effective_date,
ROW_NUMBER() OVER (PARTITION BY company_id ORDER BY effective_date) -
cnt AS grp
FROM CTE
)
SELECT company_id,
MIN(effective_date) AS start_date,
CASE
WHEN COUNT(*) > 1 THEN DATEADD(DAY, -1, MAX(effective_date))
ELSE MIN(effective_date)
END AS end_date
FROM CTE2
GROUP BY company_id, grp
HAVING COUNT(CASE WHEN status_id = 1 THEN 1 END) > 0
company_id start_date end_date
-----------------------------------
10 2016-12-15 2017-02-03
11 2018-04-30 2018-04-30