【问题标题】:Get Birthdates of employees for a period of +-30 days获取 +-30 天的员工生日
【发布时间】:2016-04-20 20:27:56
【问题描述】:

我是 SQL 的新手。对于我的 SAP 插件,我需要一个 SQL 查询来显示员工的出生日期 +-30 天(这将是最后给出的用户 int)。我根据我的理解写了一个查询,它只限制了当月的时间段。例如:如果当前日期是 2016 年 1 月 15 日,则正确的查询应显示 12 月 16 日至 2 月 14 日期间的生日。但我只看到一月份的生日。您可以查看下面的查询。

SELECT T0.[BirthDate], T0.[CardCode], T1.[CardName], T0.[Name], T0.[Tel1], 
T0.[E_MailL] FROM OCPR T0 INNER JOIN OCRD T1 ON T0.CardCode = T1.CardCode 
WHERE DATEADD( Year, DATEPART( Year, GETDATE()) - DATEPART( Year, T0.[BirthDate]), 
T0.[BirthDate]) BETWEEN CONVERT( DATE, GETDATE()-30)AND CONVERT( DATE, GETDATE() +30); 

我应该做哪些更改才能获得正确的结果? 任何帮助将不胜感激! :-)

【问题讨论】:

  • @Steve Hey 在 SAP 中,所有员工的生日都保存在一个名为 OCPR 的表中。所以想象一位员工的生日是 1957.12.25,保存在这张表中。这有什么不好?对不起,如果我糟糕的英语给你带来了错误的想法:(
  • 现在我理解得更好了

标签: sql sap


【解决方案1】:

这样的事情怎么样:

SELECT T0.[BirthDate], T0.[CardCode], T1.[CardName], T0.[Name], T0.[Tel1], T0.[E_MailL] 
FROM OCPR T0 INNER JOIN OCRD T1 ON T0.CardCode = T1.CardCode 
WHERE TO.[BirthDate] BETWEEN DATEADD(DAY, -30, GETDATE()) AND DATEADD(DAY, +30, GETDATE()) 

您可以在 cmets 中修改 answer I've referenced,如下所示:

SELECT T0.[BirthDate], T0.[CardCode], T1.[CardName], T0.[Name], T0.[Tel1], T0.[E_MailL]
FROM OCPR T0 INNER JOIN OCRD T1 ON T0.CardCode = T1.CardCode
WHERE 1 = (FLOOR(DATEDIFF(dd,TO.Birthdate,GETDATE()+30) / 365.25))
          -
          (FLOOR(DATEDIFF(dd,TO.Birthdate,GETDATE()-30) / 365.25))

根据 Vladimir 的评论,如果需要,您可以将“365.25”修改为“365.2425”以获得更高的准确性。

【讨论】:

  • 这不会给出正确的结果。 BirthDate 可以比GETDATE 返回的当前日期早很多年。
  • @VladimirBaranov - 刚刚意识到这一点,但发现了一个似乎非常相似的问题。
  • @VladimirBaranov - 在正常的一生中,这不会产生戏剧性的影响,(我认为是四分之一天)。除非您打算同时记录员工的出生时间,以便了解特定时期内 LIVE 员工的生日,否则这应该没问题。但是,为了准确起见,添加 0.2425 而不是 0.25 可能很值得。我会更新我的答案。
【解决方案2】:

我在 SQL Server 中对其进行了测试,因为它具有DATEADDGETDATE 功能。

当 +-30 天的范围跨越 1 月 1 日时,即该范围属于两年时,您的查询返回错误的结果。

你的计算

DATEADD(Year, DATEPART(Year, GETDATE()) - DATEPART( Year, T0.[BirthDate]), T0.[BirthDate])

BirthDate 的年份移动到与GETDATE 相同的年份,因此如果GETDATE 返回2016-01-01,则BirthDate=1957-12-25 变为2016-12-25。但是您的范围是从2015-12-012016-01-30 并且调整后的BirthDate 不属于它。

有很多方法可以考虑到这一年的界限。

一种可能的变体是不将2015-12-012016-01-30 的范围设为一个,而是将三个范围设为未来和前几年:

from `2014-12-01` to `2015-01-30`
from `2015-12-01` to `2016-01-30`
from `2016-12-01` to `2017-01-30`

还有一点注意——最好将原始BirthDate 与一些计算的结果进行比较,而不是转换BirthDate 并比较函数的结果。在第一种情况下优化器可以在BirthDate 上使用索引,在第二种情况下它不能。

这是我在 SQL Server 2008 中测试的完整示例。

DECLARE @T TABLE (BirthDate date);

INSERT INTO @T (BirthDate) VALUES
('2016-12-25'),
('2016-01-25'),
('2016-02-25'),
('2016-11-25'),
('2015-12-25'),
('2015-01-25'),
('2015-02-25'),
('2015-11-25'),
('2014-12-25'),
('2014-01-25'),
('2014-02-25'),
('2014-11-25');

--DECLARE @CurrDate date = '2016-01-01';
DECLARE @CurrDate date = '2015-12-31';
DECLARE @VarDays int = 30;

我使用变量@CurrDate 而不是GETDATE 来检查它在不同情况下的工作方式。

DATEDIFF(year, @CurrDate, BirthDate)@CurrDateBirthDate 之间的年份差

DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate), @CurrDate)@CurrDateBirthDate 移入同一年

最后的DATEADD(day, -@VarDays, ...)DATEADD(day, +@VarDays, ...) 构成+-@VarDays 的范围。

此范围针对“主要”以及上一年和下一年创建了 3 次。

SELECT
    BirthDate
FROM @T
WHERE
    (
        BirthDate >= DATEADD(day, -@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate), @CurrDate))
        AND
        BirthDate <= DATEADD(day, +@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate), @CurrDate))
    )
    OR
    (
        BirthDate >= DATEADD(day, -@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate)+1, @CurrDate))
        AND
        BirthDate <= DATEADD(day, +@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate)+1, @CurrDate))
    )
    OR
    (
        BirthDate >= DATEADD(day, -@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate)-1, @CurrDate))
        AND
        BirthDate <= DATEADD(day, +@VarDays, DATEADD(year, DATEDIFF(year, @CurrDate, BirthDate)-1, @CurrDate))
    )
;

结果

+------------+
| BirthDate  |
+------------+
| 2016-12-25 |
| 2016-01-25 |
| 2015-12-25 |
| 2015-01-25 |
| 2014-12-25 |
| 2014-01-25 |
+------------+

【讨论】:

  • 感谢您的详细回答。我测试后你会知道进度:)
【解决方案3】:

我已经简化了一点。我已经注释了进行计算的代码,所以将来回顾你会知道它在做什么(通常是救世主):)。

SELECT T0.[BirthDate], 
       T0.[CardCode], 
       T1.[CardName], 
       T0.[Name], 
       T0.[Tel1], 
       T0.[E_MailL]
FROM OCPR T0 
INNER JOIN OCRD T1 
ON T0.CardCode = T1.CardCode 
WHERE T0.[BirthDate] >= GETDATE()       -- Where the birthday is greater than or equal to today's date
AND   T0.[BirthDate] <= GETDATE() + 30  -- Where the birthday is less than or equal to today's date plus 30 days.

【讨论】:

  • 感谢您的及时回复。我在 SQL Management Studio 中运行了您的查询。它返回空结果。
  • 这个 Sql 不检查年份。年份必须设置为当前(如果我们在一月,则为去年)年份才能正确检查。
  • 另外,使用“AND”意味着 Birthdate 必须等于 GETDATE() 才能返回。
  • 抱歉,我一定误解了你的意图。
【解决方案4】:

您可以尝试使用 DAYOFYEAR:

SELECT T0.[BirthDate], 
       T0.[CardCode], 
       T1.[CardName], 
       T0.[Name], 
       T0.[Tel1], 
       T0.[E_MailL]
FROM OCPR T0 
INNER JOIN OCRD T1 
ON T0.CardCode = T1.CardCode
WHERE IF(DayOfYear(T0.[BirthDate]) - DayOfYear(CURDATE()) < 0, DayOfYear(T0.[BirthDate]) - DayOfYear(CURDATE()) + DayOfYear(DATE_FORMAT(CURDATE(),"%Y-12-31")), DayOfYear(T0.[BirthDate]) - DayOfYear(CURDATE())) <= 30
OR IF(DayOfYear(CURDATE()) - DayOfYear(T0.[BirthDate]) < 0, DayOfYear(CURDATE()) - DayOfYear(T0.[BirthDate]) + DayOfYear(DATE_FORMAT(CURDATE(),"%Y-12-31")), DayOfYear(CURDATE()) - DayOfYear(T0.[BirthDate])) <= 30

【讨论】:

    猜你喜欢
    • 2022-12-07
    • 2017-10-23
    • 2023-01-31
    • 2014-11-20
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 2011-08-21
    • 2015-09-27
    相关资源
    最近更新 更多