我需要创建一个报告,并且正在使用SQL脚本。 我要查询的表是company_status_history表,其中包含类似以下的条目(我不知道这些条目)
列:
nextDueDate: Sequelize.VIRTUAL
数据:
| id | company_id | status_id | effective_date |
我想回答以下问题:“获取在01/01/2017到2017年12月31日这段时间内至少处于状态1的所有公司”
上面是我不知道如何处理的情况,因为我需要添加一些类型的逻辑:
答案 0 :(得分:1)
尝试一下,不言自明。回答问题的这一部分:
我想回答以下问题:“让所有一直在 至少在时间段01/01/2017内处于状态1的某个点- 2017年12月31日”
SELECT *
FROM company_status_history
WHERE id IN
( SELECT Id
FROM company_status_history
WHERE status_id=1 )
AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
SELECT *
FROM company_status_history
WHERE status_id=1
AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
答案 1 :(得分:1)
也许这就是您想要的?对于此类问题,您需要连接表的两个实例,在这种情况下,我只是与Id的下一个记录进行连接,这可能并不完全正确。为了做得更好,您可以使用诸如row_number之类的窗口函数来创建新的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
else NULL
end
from company_status_history csh1
left join company_status_history csh2
on csh1.id=csh2.id+1
执行第二个条件:
”如果此行的状态为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
答案 2 :(得分:1)
我建议使用cte和窗口函数ROW_NUMBER。这样您可以找到所需的记录。一个例子:
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
我首先选择所有记录的前导日期和滞后日期,然后在所需的时间范围内对包含的内容进行检查。
答案 3 :(得分:1)
我认为这可以作为缺口和孤岛问题解决。考虑以下输入数据:(与OP的样本数据相同,外加两行)
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
现在,您可以使用以下命令来识别status = 1
个岛屿:
;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
计算字段grp
将帮助我们识别这些岛屿:
;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
所有您想知道的是那些从上方以指定间隔重叠的记录。
Demo here和更复杂的用例。