如何将一个SQL表中的日期与另一个表中定义的范围进行比较?

时间:2013-07-16 16:34:21

标签: sql sql-server stored-procedures

我有一张表,其中包含事件和日期:

 NAME  | DOB
 -------------------
 Adam  | 6/26/1999
 Barry | 7/18/2005
 Daniel| 1/18/1984

我有另一个表格,将日期范围定义为开始或结束时间,每个表格都有一个描述性代码:

 CODE      | DATE
 ---------------------
 YearStart| 6/28/2013
 YearEnd  | 8/14/2013

我正在尝试编写SQL,它将查找介于第二个表中描述的时间的开始和结束之间的所有出生日期。 YearStart将始终在六月,而YearEnd将始终在八月。我的想法是尝试:

 SELECT 
      u.Name
      CAST(MONTH(u.DOB) AS varchar) + '/' + CAST(DAY(u.DOB) AS varchar) as 'Birthdate',
      u.DOB as 'Birthday'
 FROM 
      Users u
 WHERE
      MONTH(DOB) = '7' OR
      (MONTH(DOB) = '6' AND DAY(DOB) >= DAY(SELECT d.Date FROM Dates d WHERE d.Code='YearStart')) OR
      (MONTH(DOB) = '8' AND DAY(DOB) <= DAY(SELECT d.Date FROM Dates d WHERE d.Code='YearEnd')))
 ORDER BY
      MONTH(DOB) ASC, DAY(DOB) ASC

但是这没有通过,我猜是因为无法保证内部SELECT语句只会返回一行,因此无法解析为日期时间。我如何实际完成此查询?

3 个答案:

答案 0 :(得分:2)

这看起来很奇怪,我仍然觉得我们错过了相关的要求,但请看下面的内容。从您的描述中可以看出,这些年份无关紧要,您希望生日落在给定的月/天之间。

SELECT 
    t1.Name, t1.DOB
FROM 
    t1
    JOIN t2 AS startDate ON (startDate.Code = 'YearStart')
    JOIN t2 AS endDate ON (endDate.Code = 'YearEnd')
WHERE 
    STUFF(CONVERT(varchar, t1.DOB, 112), 1, 4, '') BETWEEN 
        STUFF(CONVERT(varchar, startDate.[Date], 112), 1, 4, '')
        AND
        STUFF(CONVERT(varchar, endDate.[Date], 112), 1, 4, '')  

答案 1 :(得分:0)

尝试使用PIVOT来获取同一行的年份,就像这样。这将只返回'Bob'

DECLARE @Names TABLE(
NAME VARCHAR(20),
DOB VARCHAR(10));

DECLARE @Dates TABLE(
CODE VARCHAR(20),
THEDATE VARCHAR(10));

INSERT @Names (NAME,DOB) VALUES ('Adam', '6/26/1999');
INSERT @Names (NAME,DOB) VALUES ('Daniel', '1/18/1984');
INSERT @Names (NAME,DOB) VALUES ('Bob', '7/1/2013');

INSERT @Dates (CODE,THEDATE) VALUES ('YearStart', '6/28/2013');
INSERT @Dates (CODE,THEDATE) VALUES ('YearEnd', '8/14/2013');

SELECT * FROM @Names;
SELECT * FROM @Dates;

SELECT n.*
FROM @Names AS n
INNER JOIN (
    SELECT
            1 AS YearTypeId 
          , [YearStart]
          , [YearEnd]      
    FROM    ( SELECT    [CODE]
                      , THEDATE
              FROM      @Dates
            ) p PIVOT ( MIN(THEDATE)
                        FOR [CODE] 
                          IN ([YearStart],[YearEnd])
                      ) AS pvt) AS y
ON 
    n.DOB >= y.YearStart 
    AND n.DOB <= y.YearEnd       

答案 2 :(得分:0)

从你问题的最后一段开始,我假设Dates表每年有一个YearStart和一个YearEnd行,对吗?如果是这样,您的SQL查询应包括您感兴趣的年份。

此外,即使“日期”严格来说不是SQL Server的保留字(请参阅Reserved Keywords for Transact SQL),也应避免使用此类列名,因为例如,ODBC不允许使用它们。

但要仅使用您已经提供的信息做某事,您可以做类似的事情来获得Dates中定义的去年的生日庆祝者(假设那一年确实存在YearStart和YearEnd条目) :

SELECT DISTINCT <the rest as in your example>
 FROM  Users u
 WHERE u.DOB >= (SELECT max(d1.Date) FROM Dates d1 WHERE d1.Code = 'YearStart')
  AND  u.DOB <= (SELECT max(d2.Date) FROM Dates d2 WHERE d2.Code = 'YearEnd')
 ORDER BY u.DOB;

上面的查询之间的主要区别(我没有测试过 - 这只是为了显示原理)和你的帖子是我相信日期时间类型(或者你在数据库中使用的任何变体)到按预期工作。我的意思是数据库引擎很清楚(好吧,应该)两个完整日期中哪一个是最早的和最新的 - 你不必提取和比较它们的组件分开。

/ Bosse的