I have a table EMPLOYEE containing Employee info as mentioned below:
我有一个包含员工信息的表EMPLOYEE,如下所述:
ID NAME DOB
1 ABC 1974-01-01
2 BDS 1984-12-31
3 QWE 1959-05-27
and so on
I want to list all the employees whose DOB is in the given range.
我想列出DOB在给定范围内的所有员工。
select * from EMPLOYEE where DOB BETWEEN '1970-01-01' AND '1980-02-27'
I have a filter condition to 'include year in date comparison', which when selected 'NO', the employee DOB day and DOB month only should be considered for comparison. and not the year.
我有一个过滤条件'包括年度比较',当选择'否'时,员工DOB日和DOB月只应考虑进行比较。而不是一年。
For example: If I enter the date range as '1970-01-01' and '1980-02-27' and the filter is selected as 'NO' then it should search for only those employees whose DOB is greater than equal to JAN-01 and less than equal to FEB-27.
例如:如果我输入日期范围为'1970-01-01'和'1980-02-27'并且过滤器被选为'NO',那么它应该仅搜索那些DOB大于等于JAN的员工-01且小于等于FEB-27。
When selected 'Yes', it is simply date range as mentioned in above query.
选择“是”时,它只是上面查询中提到的日期范围。
Here is what I have tried so far:
这是我到目前为止所尝试的:
select * from EMPLOYEE where DOB BETWEEN '1970-01-01' AND '1980-02-27'
AND MONTH(DOB) >= CASE WHEN 'NO'='NO' THEN MONTH('1970-01-01')
ELSE MONTH(DOB) END
AND MONTH(DOB) <= CASE WHEN 'NO'='NO' THEN MONTH('1980-02-27')
ELSE MONTH(DOB) END
AND DAY(DOB) >= CASE WHEN 'NO'='NO' THEN DAY('1970-01-01')
ELSE DAY(DOB) END
AND DAY(DOB) <= CASE WHEN 'NO'='NO' THEN DAY('1980-02-27')
ELSE DAY(DOB) END
It works when I pass the date range where the FROM date has smaller number month than the TO date month.
当我通过日期范围时,它的工作日期范围,其中FROM日期的月份数小于TO日期月份。
For example: It doesnt work when I pass the date range as '1970-12-01' to '1980-01-31'. It should list the employees whose DOB is in DEC and JAN month.
例如:当我将日期范围作为'1970-12-01'传递给'1980-01-31'时,它不起作用。它应列出DOB在DEC和JAN月份的员工。
Need help please.
需要帮助。
7 个解决方案
#1
2
Sample Data;
DECLARE @Date_From date; SET @Date_From = '1970-12-01'
DECLARE @Date_To date; SET @Date_To = '1974-01-31'
DECLARE @IncludeYear bit; SET @IncludeYear = 0
CREATE TABLE #Employee (ID int, Name varchar(10), DOB date)
INSERT INTO #Employee (ID, Name, DOB)
VALUES
(1,'ABC','1974-01-01')
,(2,'BDS','1984-12-31')
,(3,'QWE','1959-05-27')
This is the query I've made. Tried to cover for every eventuality.
这是我的查询。试图弥补每一个可能性。
SELECT
e.ID
,e.Name
,e.DOB
FROM #Employee e
WHERE
(
@IncludeYear = 1
AND
DOB BETWEEN @Date_From AND @Date_To
)
OR
(
@IncludeYear = 0
AND
(
(
DATEPART(DAYOFYEAR, @Date_From) = DATEPART(DAYOFYEAR, @Date_To)
AND
DATEPART(DAYOFYEAR, DOB) = DATEPART(DAYOFYEAR, @Date_To)
)
OR
(
DATEPART(DAYOFYEAR, @Date_From) < DATEPART(DAYOFYEAR, @Date_To)
AND
DATEPART(DAYOFYEAR, DOB) BETWEEN DATEPART(DAYOFYEAR, @Date_From) AND DATEPART(DAYOFYEAR, @Date_To)
)
OR
(
DATEPART(DAYOFYEAR, @Date_From) > DATEPART(DAYOFYEAR, @Date_To)
AND
(
DATEPART(DAYOFYEAR, DOB) > DATEPART(DAYOFYEAR, @Date_From)
OR
DATEPART(DAYOFYEAR, DOB) < DATEPART(DAYOFYEAR, @Date_To)
)
)
)
)
- First part of the where clause checks if the @date_from and @date_to are the same date, then only returns these.
- Second part checks if the day of year for @date_from comes before @date_to. If it does then return everything between these days of the year.
- Final part checks if the day of year for @date_to comes before @date_from then it gets everything with the day of year after @date_from or before @date_to
where子句的第一部分检查@date_from和@date_to是否是相同的日期,然后只返回这些。
第二部分检查@date_from的日期是否在@date_to之前。如果确实如此,则在一年中的这几天之间返回所有内容。
最后一部分检查@date_to的日期是否在@date_from之前,然后在@date_from之后或@date_to之前获得一年中的所有日期
The results for this one come out as this;
这个的结果就是这样的;
ID Name DOB
1 ABC 1974-01-01
2 BDS 1984-12-31
#2
2
DECLARE @includeYear bit = 0, -- if 0 - we don't include year, 1 - include
@dateFrom date ='1970-12-01',
@dateTo date ='1980-05-30'
IF @includeYear = 1
BEGIN
SELECT e.*
FROM EMPLOYEE e
INNER JOIN (SELECT @dateFrom as dF, @dateTo as dT) d
ON e.DOB BETWEEN dF AND dT
END
ELSE
BEGIN
SELECT e.*
FROM EMPLOYEE e
INNER JOIN (SELECT @dateFrom as dF, @dateTo as dT) d
ON e.DOB BETWEEN
(CASE WHEN MONTH(dF) > MONTH(dT)
THEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dF)-1,dF)
ELSE DATEADD(year,YEAR(e.DOB)-YEAR(d.dF),dF) END)
AND DATEADD(year,YEAR(e.DOB)-YEAR(d.dT),dT)
OR e.DOB BETWEEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dF),dF) AND
(CASE WHEN MONTH(dF) > MONTH(dT)
THEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dT)+1,dT)
ELSE DATEADD(year,YEAR(e.DOB)-YEAR(d.dT),dT) END)
END
For
dateFrom dateTo
1970-12-01 1980-01-30
Output:
ID NAME DOB
1 ABC 1974-01-01
2 BDS 1984-12-31
For
dateFrom dateTo
1970-05-01 1980-06-30
Output:
ID NAME DOB
3 QWE 1959-05-27
For
dateFrom dateTo
1970-05-01 1980-05-30
Output:
ID NAME DOB
3 QWE 1959-05-27
etc
#3
0
Try the function DATEPART(dayofyear, date)
In case the day-of-year of the first date is smaller than the day-of-year of the second date, then the day-of-year of the DOB should be between the specified days-of-year.
Otherwise, the day-of-year of the DOB should be either smaller than the day-of-year of the second date or greater than the day-of-year of the first date.
尝试DATEPART函数(dayofyear,date)如果第一个日期的年份小于第二个日期的日期,那么DOB的年份应该在指定的年份之间天的一年。否则,DOB的年度应小于第二个日期的日期或大于第一个日期的日期。
I hope I expressed myself well.
我希望我表达得很好。
#4
0
Rather than working case-by-case and disassembling and reassembling parts of dates, I've tried to make life easier:
我试图让生活更轻松,而不是逐案工作,拆解和重新组装部分日期:
declare @t table (ID int not null, Name varchar(17) not null, DOB date not null)
insert into @t(ID,NAME,DOB) values
(1,'ABC','19740101'),
(2,'BDS','19841231'),
(3,'QWE','19590527')
declare @Start date
declare @End date
declare @IncludeYear bit
select @Start='19701201',@End='19800131',@IncludeYear=0
;With Normalized as (
select
ID,
Name,
CASE WHEN @IncludeYear=1 THEN DOB
ELSE DATEADD(year,DATEDIFF(year,DOB,'20000101'),DOB)
END as DOB,
CASE WHEN @IncludeYear=1 THEN @Start
ELSE DATEADD(year,DATEDIFF(year,@Start,'20000101'),@Start)
END as StartRange,
CASE WHEN @IncludeYear=1 THEN @End
ELSE DATEADD(year,DATEDIFF(year,@End,'20000101'),@End)
END as EndRange
from
@t
)
select * from Normalized
where
DOB between StartRange and EndRange or
(
@IncludeYear=0 and StartRange>EndRange and
(
DOB < EndRange or DOB > StartRange
)
)
We create the Normalized
CTE that, does nothing if @IncludeYear
is 1 or, if it is zero, it resets all dates so that they occur in 2000 (arbitrarily selected).
我们创建标准化CTE,如果@IncludeYear为1则不执行任何操作,或者如果它为零,则重置所有日期,以便它们出现在2000(任意选择)。
We then do the straightforward query based on the CTE. The one circumstance where it won't correctly match is when you have your range defined over a year-end transition and we don't care about years - which we can check specifically for and cater for within the end of the WHERE
clause.
然后,我们根据CTE进行简单的查询。它不能正确匹配的一种情况是,您在年终转换中定义了您的范围,而我们不关心年份 - 我们可以在WHERE子句的末尾专门检查和满足。
Results:
ID Name DOB StartRange EndRange
----------- ----------------- ---------- ---------- ----------
1 ABC 2000-01-01 2000-12-01 2000-01-31
2 BDS 2000-12-31 2000-12-01 2000-01-31
Results with @Start='19700101',@End='19800227',@IncludeYear=1
:
结果@ Start ='19700101',@ End ='19800227',@ IncludeYear = 1:
ID Name DOB StartRange EndRange
----------- ----------------- ---------- ---------- ----------
1 ABC 1974-01-01 1970-01-01 1980-02-27
#5
0
Here is another solution
这是另一种解决方案
DECLARE @employee table(EmployeeID varchar(10), DOB date);
INSERT INTO @employee(EmployeeID, DOB)
VALUES('0001', '01-Dec-1990'),
('0002', '06-Jan-1993'),
('0003', '04-Mar-1987'),
('0004', '12-Feb-1996');
DECLARE @dateStart date = '01-Jan-1990';
DECLARE @dateEnd date = '27-Feb-1997';
DECLARE @includeYear bit = 0;
If @includeYear = 0
Begin
SET @dateStart = CAST(('2000-' + CAST(MONTH(@dateStart) AS varchar(10)) + '-' + CAST(DAY(@dateStart) as varchar(10))) AS date);
SET @dateEnd = CAST(('2000-' + CAST(MONTH(@dateEnd) AS varchar(10)) + '-' + CAST(DAY(@dateEnd) as varchar(10))) AS date);
End
If @includeYear = 1
Begin
SELECT *
FROM @employee
WHERE DOB BETWEEN @dateStart AND @dateEnd
End
Else
Begin
SELECT *
FROM @employee
WHERE CAST(('2000-' + CAST(MONTH(DOB) AS varchar(10)) + '-' + CAST(DAY(DOB) as varchar(10))) AS date) BETWEEN @dateStart AND @dateEnd
End
As you can see we are just making the year part of the query a constant if you don't want to include year. This query seems to be a bit slower but if you add another computed column in your table, where you save the date with a constant year then you just need to put where criteria on that particular column.
正如您所看到的,如果您不想包含年份,我们只是将查询的年份作为常量。这个查询似乎有点慢但是如果你在表中添加另一个计算列,你用一个常数年保存日期,那么你只需要在那个特定列上放置标准。
#6
0
Try this.
declare @flag varchar(3) ='NO';
declare @sd date ='1980-02-27';
declare @ed date ='1970-01-01';
select tt.*
from (select sd = month(@sd)*100 + day(@sd),
ed = month(@ed)*100 + day(@ed)
) prm
cross join
-- test data, place real table here
(
values
(1,'ABC', cast('1974-01-05' as date)),
(2,'BDS','1984-12-31'),
(3,'QWE','1959-05-27')
) tt(ID,NAME, DOB)
cross apply (select md = month(DOB)*100 + day(DOB)) tx
where @flag ='YES' and DOB between @sd and @ed
or @flag ='NO' and (prm.sd<=prm.ed and tx.md between prm.sd and prm.ed
or prm.sd>prm.ed and (tx.md <= prm.ed or tx.md >= prm.sd));
#7
0
- Always use a SARG in your predicate. Any answer that fails to do this only results in lost performance and your DBA getting upset.
始终在谓词中使用SARG。任何未能做到这一点的答案只会导致性能下降和DBA感到不安。
What you want is two different queries to run depending on the answer to the Procedure. Since this is a proc that likely runs a lot, store the answers into a variable in your PROC and run any adjusting code from there. Not only will this make your code more robust by flushing out errors beforehand, but SQL Server has a better chance of guessing the variables to use with your indexes.
您想要的是根据过程的答案运行两个不同的查询。由于这是一个可能会运行很多的过程,因此将答案存储到PROC中的变量中并从那里运行任何调整代码。通过预先清除错误,这不仅可以使您的代码更加健壮,而且SQL Server更有可能猜测要与索引一起使用的变量。
The following PROC will work. Feel free to use part or all of it:
以下PROC将起作用。随意使用部分或全部:
CREATE TABLE #table_E (ID INT, Name VARCHAR(3), DOB DATE)
INSERT INTO #table_E (ID , Name, DOB)
VALUES (1, 'ABC', '1997-01-02' )
, (2, 'BDS', '1984-12-31' )
, (3, 'QWE', '1993-03-22' )
GO
CREATE PROC USP_EmpCompare (@Date_1 DATE, @Date_2 DATE, @Compare_Year VARCHAR(3))
AS
BEGIN
DECLARE @MONTH_1 INT
, @Month_2 INT
, @Day_1 INT
, @Day_2 INT
, @Date1 DATE
, @Date2 DATE
SET @Date1 = CASE WHEN @Date_1 > @Date_2 THEN @Date_2 ELSE @Date_1 END
SET @Date2 = CASE WHEN @Date_1 > @Date_2 THEN @Date_1 ELSE @Date_2 END
SET @Month_1 = CASE WHEN DATEPART(MM, @Date2) > DATEPART(MM, @Date1) THEN DATEPART(MM, @Date1) ELSE DATEPART(MM, @Date2) END
SET @Month_2 = CASE WHEN DATEPART(MM, @Date1) > DATEPART(MM, @Date2) THEN DATEPART(MM, @Date1) ELSE DATEPART(MM, @Date2) END
SET @Day_1 = CASE WHEN DATEPART(DD, @Date2) > DATEPART(DD, @Date1) THEN DATEPART(DD, @Date1) ELSE DATEPART(DD, @Date2) END
SET @Day_2 = CASE WHEN DATEPART(DD, @Date1) > DATEPART(DD, @Date2) THEN DATEPART(DD, @Date1) ELSE DATEPART(DD, @Date2) END
-- SELECT @Date1, @Date2
IF @Compare_Year = 'no'
BEGIN
;WITH C AS (SELECT ID
, Name
, DATEPART(DD, DOB) AS Day
, DATEPART(MM, DOB) AS Month
FROM #table_E)
SELECT ID, Name, @Date1, @Date2
FROM C
WHERE C.Month >= @MONTH_1
AND C.Month <= @Month_2
AND C.Day >= @Day_1
AND C.DAy <= @Day_2
END
IF @Compare_Year = 'yes'
BEGIN
SELECT ID, Name, DOB
FROM #table_E
WHERE DOB <= @Date2
AND DOB >= @Date1
END
ELSE
PRINT WHAT! FOLLOW THE RULES YOU FOOL!!!
END
jk. that last part about fools is probably not included in your final draft. ;)
JK。关于傻瓜的最后一部分可能不包括在你的最终草案中。 ;)
#1
2
Sample Data;
DECLARE @Date_From date; SET @Date_From = '1970-12-01'
DECLARE @Date_To date; SET @Date_To = '1974-01-31'
DECLARE @IncludeYear bit; SET @IncludeYear = 0
CREATE TABLE #Employee (ID int, Name varchar(10), DOB date)
INSERT INTO #Employee (ID, Name, DOB)
VALUES
(1,'ABC','1974-01-01')
,(2,'BDS','1984-12-31')
,(3,'QWE','1959-05-27')
This is the query I've made. Tried to cover for every eventuality.
这是我的查询。试图弥补每一个可能性。
SELECT
e.ID
,e.Name
,e.DOB
FROM #Employee e
WHERE
(
@IncludeYear = 1
AND
DOB BETWEEN @Date_From AND @Date_To
)
OR
(
@IncludeYear = 0
AND
(
(
DATEPART(DAYOFYEAR, @Date_From) = DATEPART(DAYOFYEAR, @Date_To)
AND
DATEPART(DAYOFYEAR, DOB) = DATEPART(DAYOFYEAR, @Date_To)
)
OR
(
DATEPART(DAYOFYEAR, @Date_From) < DATEPART(DAYOFYEAR, @Date_To)
AND
DATEPART(DAYOFYEAR, DOB) BETWEEN DATEPART(DAYOFYEAR, @Date_From) AND DATEPART(DAYOFYEAR, @Date_To)
)
OR
(
DATEPART(DAYOFYEAR, @Date_From) > DATEPART(DAYOFYEAR, @Date_To)
AND
(
DATEPART(DAYOFYEAR, DOB) > DATEPART(DAYOFYEAR, @Date_From)
OR
DATEPART(DAYOFYEAR, DOB) < DATEPART(DAYOFYEAR, @Date_To)
)
)
)
)
- First part of the where clause checks if the @date_from and @date_to are the same date, then only returns these.
- Second part checks if the day of year for @date_from comes before @date_to. If it does then return everything between these days of the year.
- Final part checks if the day of year for @date_to comes before @date_from then it gets everything with the day of year after @date_from or before @date_to
where子句的第一部分检查@date_from和@date_to是否是相同的日期,然后只返回这些。
第二部分检查@date_from的日期是否在@date_to之前。如果确实如此,则在一年中的这几天之间返回所有内容。
最后一部分检查@date_to的日期是否在@date_from之前,然后在@date_from之后或@date_to之前获得一年中的所有日期
The results for this one come out as this;
这个的结果就是这样的;
ID Name DOB
1 ABC 1974-01-01
2 BDS 1984-12-31
#2
2
DECLARE @includeYear bit = 0, -- if 0 - we don't include year, 1 - include
@dateFrom date ='1970-12-01',
@dateTo date ='1980-05-30'
IF @includeYear = 1
BEGIN
SELECT e.*
FROM EMPLOYEE e
INNER JOIN (SELECT @dateFrom as dF, @dateTo as dT) d
ON e.DOB BETWEEN dF AND dT
END
ELSE
BEGIN
SELECT e.*
FROM EMPLOYEE e
INNER JOIN (SELECT @dateFrom as dF, @dateTo as dT) d
ON e.DOB BETWEEN
(CASE WHEN MONTH(dF) > MONTH(dT)
THEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dF)-1,dF)
ELSE DATEADD(year,YEAR(e.DOB)-YEAR(d.dF),dF) END)
AND DATEADD(year,YEAR(e.DOB)-YEAR(d.dT),dT)
OR e.DOB BETWEEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dF),dF) AND
(CASE WHEN MONTH(dF) > MONTH(dT)
THEN DATEADD(year,YEAR(e.DOB)-YEAR(d.dT)+1,dT)
ELSE DATEADD(year,YEAR(e.DOB)-YEAR(d.dT),dT) END)
END
For
dateFrom dateTo
1970-12-01 1980-01-30
Output:
ID NAME DOB
1 ABC 1974-01-01
2 BDS 1984-12-31
For
dateFrom dateTo
1970-05-01 1980-06-30
Output:
ID NAME DOB
3 QWE 1959-05-27
For
dateFrom dateTo
1970-05-01 1980-05-30
Output:
ID NAME DOB
3 QWE 1959-05-27
etc
#3
0
Try the function DATEPART(dayofyear, date)
In case the day-of-year of the first date is smaller than the day-of-year of the second date, then the day-of-year of the DOB should be between the specified days-of-year.
Otherwise, the day-of-year of the DOB should be either smaller than the day-of-year of the second date or greater than the day-of-year of the first date.
尝试DATEPART函数(dayofyear,date)如果第一个日期的年份小于第二个日期的日期,那么DOB的年份应该在指定的年份之间天的一年。否则,DOB的年度应小于第二个日期的日期或大于第一个日期的日期。
I hope I expressed myself well.
我希望我表达得很好。
#4
0
Rather than working case-by-case and disassembling and reassembling parts of dates, I've tried to make life easier:
我试图让生活更轻松,而不是逐案工作,拆解和重新组装部分日期:
declare @t table (ID int not null, Name varchar(17) not null, DOB date not null)
insert into @t(ID,NAME,DOB) values
(1,'ABC','19740101'),
(2,'BDS','19841231'),
(3,'QWE','19590527')
declare @Start date
declare @End date
declare @IncludeYear bit
select @Start='19701201',@End='19800131',@IncludeYear=0
;With Normalized as (
select
ID,
Name,
CASE WHEN @IncludeYear=1 THEN DOB
ELSE DATEADD(year,DATEDIFF(year,DOB,'20000101'),DOB)
END as DOB,
CASE WHEN @IncludeYear=1 THEN @Start
ELSE DATEADD(year,DATEDIFF(year,@Start,'20000101'),@Start)
END as StartRange,
CASE WHEN @IncludeYear=1 THEN @End
ELSE DATEADD(year,DATEDIFF(year,@End,'20000101'),@End)
END as EndRange
from
@t
)
select * from Normalized
where
DOB between StartRange and EndRange or
(
@IncludeYear=0 and StartRange>EndRange and
(
DOB < EndRange or DOB > StartRange
)
)
We create the Normalized
CTE that, does nothing if @IncludeYear
is 1 or, if it is zero, it resets all dates so that they occur in 2000 (arbitrarily selected).
我们创建标准化CTE,如果@IncludeYear为1则不执行任何操作,或者如果它为零,则重置所有日期,以便它们出现在2000(任意选择)。
We then do the straightforward query based on the CTE. The one circumstance where it won't correctly match is when you have your range defined over a year-end transition and we don't care about years - which we can check specifically for and cater for within the end of the WHERE
clause.
然后,我们根据CTE进行简单的查询。它不能正确匹配的一种情况是,您在年终转换中定义了您的范围,而我们不关心年份 - 我们可以在WHERE子句的末尾专门检查和满足。
Results:
ID Name DOB StartRange EndRange
----------- ----------------- ---------- ---------- ----------
1 ABC 2000-01-01 2000-12-01 2000-01-31
2 BDS 2000-12-31 2000-12-01 2000-01-31
Results with @Start='19700101',@End='19800227',@IncludeYear=1
:
结果@ Start ='19700101',@ End ='19800227',@ IncludeYear = 1:
ID Name DOB StartRange EndRange
----------- ----------------- ---------- ---------- ----------
1 ABC 1974-01-01 1970-01-01 1980-02-27
#5
0
Here is another solution
这是另一种解决方案
DECLARE @employee table(EmployeeID varchar(10), DOB date);
INSERT INTO @employee(EmployeeID, DOB)
VALUES('0001', '01-Dec-1990'),
('0002', '06-Jan-1993'),
('0003', '04-Mar-1987'),
('0004', '12-Feb-1996');
DECLARE @dateStart date = '01-Jan-1990';
DECLARE @dateEnd date = '27-Feb-1997';
DECLARE @includeYear bit = 0;
If @includeYear = 0
Begin
SET @dateStart = CAST(('2000-' + CAST(MONTH(@dateStart) AS varchar(10)) + '-' + CAST(DAY(@dateStart) as varchar(10))) AS date);
SET @dateEnd = CAST(('2000-' + CAST(MONTH(@dateEnd) AS varchar(10)) + '-' + CAST(DAY(@dateEnd) as varchar(10))) AS date);
End
If @includeYear = 1
Begin
SELECT *
FROM @employee
WHERE DOB BETWEEN @dateStart AND @dateEnd
End
Else
Begin
SELECT *
FROM @employee
WHERE CAST(('2000-' + CAST(MONTH(DOB) AS varchar(10)) + '-' + CAST(DAY(DOB) as varchar(10))) AS date) BETWEEN @dateStart AND @dateEnd
End
As you can see we are just making the year part of the query a constant if you don't want to include year. This query seems to be a bit slower but if you add another computed column in your table, where you save the date with a constant year then you just need to put where criteria on that particular column.
正如您所看到的,如果您不想包含年份,我们只是将查询的年份作为常量。这个查询似乎有点慢但是如果你在表中添加另一个计算列,你用一个常数年保存日期,那么你只需要在那个特定列上放置标准。
#6
0
Try this.
declare @flag varchar(3) ='NO';
declare @sd date ='1980-02-27';
declare @ed date ='1970-01-01';
select tt.*
from (select sd = month(@sd)*100 + day(@sd),
ed = month(@ed)*100 + day(@ed)
) prm
cross join
-- test data, place real table here
(
values
(1,'ABC', cast('1974-01-05' as date)),
(2,'BDS','1984-12-31'),
(3,'QWE','1959-05-27')
) tt(ID,NAME, DOB)
cross apply (select md = month(DOB)*100 + day(DOB)) tx
where @flag ='YES' and DOB between @sd and @ed
or @flag ='NO' and (prm.sd<=prm.ed and tx.md between prm.sd and prm.ed
or prm.sd>prm.ed and (tx.md <= prm.ed or tx.md >= prm.sd));
#7
0
- Always use a SARG in your predicate. Any answer that fails to do this only results in lost performance and your DBA getting upset.
始终在谓词中使用SARG。任何未能做到这一点的答案只会导致性能下降和DBA感到不安。
What you want is two different queries to run depending on the answer to the Procedure. Since this is a proc that likely runs a lot, store the answers into a variable in your PROC and run any adjusting code from there. Not only will this make your code more robust by flushing out errors beforehand, but SQL Server has a better chance of guessing the variables to use with your indexes.
您想要的是根据过程的答案运行两个不同的查询。由于这是一个可能会运行很多的过程,因此将答案存储到PROC中的变量中并从那里运行任何调整代码。通过预先清除错误,这不仅可以使您的代码更加健壮,而且SQL Server更有可能猜测要与索引一起使用的变量。
The following PROC will work. Feel free to use part or all of it:
以下PROC将起作用。随意使用部分或全部:
CREATE TABLE #table_E (ID INT, Name VARCHAR(3), DOB DATE)
INSERT INTO #table_E (ID , Name, DOB)
VALUES (1, 'ABC', '1997-01-02' )
, (2, 'BDS', '1984-12-31' )
, (3, 'QWE', '1993-03-22' )
GO
CREATE PROC USP_EmpCompare (@Date_1 DATE, @Date_2 DATE, @Compare_Year VARCHAR(3))
AS
BEGIN
DECLARE @MONTH_1 INT
, @Month_2 INT
, @Day_1 INT
, @Day_2 INT
, @Date1 DATE
, @Date2 DATE
SET @Date1 = CASE WHEN @Date_1 > @Date_2 THEN @Date_2 ELSE @Date_1 END
SET @Date2 = CASE WHEN @Date_1 > @Date_2 THEN @Date_1 ELSE @Date_2 END
SET @Month_1 = CASE WHEN DATEPART(MM, @Date2) > DATEPART(MM, @Date1) THEN DATEPART(MM, @Date1) ELSE DATEPART(MM, @Date2) END
SET @Month_2 = CASE WHEN DATEPART(MM, @Date1) > DATEPART(MM, @Date2) THEN DATEPART(MM, @Date1) ELSE DATEPART(MM, @Date2) END
SET @Day_1 = CASE WHEN DATEPART(DD, @Date2) > DATEPART(DD, @Date1) THEN DATEPART(DD, @Date1) ELSE DATEPART(DD, @Date2) END
SET @Day_2 = CASE WHEN DATEPART(DD, @Date1) > DATEPART(DD, @Date2) THEN DATEPART(DD, @Date1) ELSE DATEPART(DD, @Date2) END
-- SELECT @Date1, @Date2
IF @Compare_Year = 'no'
BEGIN
;WITH C AS (SELECT ID
, Name
, DATEPART(DD, DOB) AS Day
, DATEPART(MM, DOB) AS Month
FROM #table_E)
SELECT ID, Name, @Date1, @Date2
FROM C
WHERE C.Month >= @MONTH_1
AND C.Month <= @Month_2
AND C.Day >= @Day_1
AND C.DAy <= @Day_2
END
IF @Compare_Year = 'yes'
BEGIN
SELECT ID, Name, DOB
FROM #table_E
WHERE DOB <= @Date2
AND DOB >= @Date1
END
ELSE
PRINT WHAT! FOLLOW THE RULES YOU FOOL!!!
END
jk. that last part about fools is probably not included in your final draft. ;)
JK。关于傻瓜的最后一部分可能不包括在你的最终草案中。 ;)