需要 SQL 游标建议 - 检查一组日期范围内的唯一日期列表



我是自学成才的T-SQL,所以如果我问一个答案简单的问题,请原谅我,但我已经达到了我知识的尽头,我的互联网搜索并没有教我我正在寻找的东西......

我有两个我正在使用的表:

tbl_A (exit)
----------------------------
id_num | exit_dte
----------------------------
100001 | 2001-01-15
100002 | 2001-01-31
100003 | 2001-06-03
tbl_B (period)
---------------------------------------------
period_id | period_start_dte | period_end_dte
---------------------------------------------
1 |       2001-01-01 |     2001-01-31
2 |       2001-07-01 |     2001-07-31

系统界面允许数据用户将他们想要的任何日期放入 tbl_A.exit_dte,尽管他们的(不成文的)业务策略规定他们不应将日期放入不在tbl_B中记录的period_start_dte和period_end_dte之间的列中。我需要找到任何不在period_id开始和结束之间的exit_dte。

我的第一步是准备现有 tbl_A.exit_dte 值的不同列表。这个我知道该怎么做:

Select distinct tbl_A.exit_dte from tbl_A

我不知道该怎么做,但我想我想做的是使用光标遍历此列表的值,并为每个值确定它是否介于tbl_B中某个时间段的开始日期和结束日期之间。如果在时间段日期范围内,我将显示"在范围内";否则,我会显示"错误"(描述符无关紧要,我明白)。

2001-01-15 | In Range  (matches tbl_B.period_id = 1)
2001-01-31 | In Range  (matches tbl_B.period_id = 1) 
2001-06-03 | Error

以下是我为了获得预期结果而尝试的方法:

Declare @ques_dte datetime
Declare @Getid cursor
Set @Getid = CURSOR FOR
Select distinct exit_dte
from tbl_A
Open @Getid
Fetch NEXT
from @Getid into @ques_dte
while @@FETCH_STATUS = 0
Begin
select
@ques_dte as checked_date
, case 
when tbl_B.period_id is not null then 'In Range'
else 'Error' end as Date_Period_Check
from tbl_B
where @ques_dte between tbl_B.period_start_dte and tbl_B.period_end_dte
Fetch NEXT
From @Getid INTO @ques_dte
END
Close @Getid
Deallocate @Getid

因此,当我运行查询时,查询不会爆炸(总是一个好兆头),但是有几个问题。首先,SSMS 中的结果使其看起来像是针对每个@ques_dte值运行不同的查询(可能是),而不是一长组结果。我敢肯定,这是由于我对开始,获取,结束的CURSOR操作的理解不正确。

其次,虽然查询显示与 tbl_B.period_id匹配@ques_dte,并显示"范围内"值,但不匹配的@ques_dte不显示@ques_dte或"错误"值 - 它只是一个空记录集。我对此感到困惑。

第三,(这可能是因为我不耐烦,不理解基于集的SQL操作之间的区别,不管这是什么......)查询似乎需要很长时间才能运行。在我的生产环境中,tbl_B中有 164 条记录,tbl_A中有不同的查询中有 1011 条记录。这些数字看起来很小,但查询需要 29 秒才能完成。

我欢迎专家的反馈和建议。我真的不太在乎执行时间 - 我可以忍受延迟 - 但如果有人愿意在我的前两个问题上教育我,我将非常感激。

在我看来,一个简单的左连接就可以了:

SELECT id_num, exit_dte, period_id
FROM [exit] 
LEFT JOIN period 
ON exit_dte > period_statt_dte
AND exit_dte < period_end_dte

对于属于某个范围的日期,您将获得范围的period_id,对于不属于某个范围的日期,您将获得 null。

如果要显示"范围内"和"错误",可以使用以下情况:

SELECT  exit_dte, 
CASE WHEN period_id IS NOT NULL THEN 
'In Range' 
ELSE
'Error' 
END
FROM [exit] 
LEFT JOIN period 
ON exit_dte > period_statt_dte
AND exit_dte < period_end_dte

这将是您需要的,它将基于一组数据完成,而不是在第二个表的每一行上逐一进行(就像光标所做的那样):

select id_num, exit_dte 
from table1 t1 left join table2 t2 on t1.exit_dte between period_start_dte and period_end_dte
where t2.period_id is null 

最新更新