SQL-查找列日期是否至少部分包含日期范围

SQL-查找列日期是否至少部分包含日期范围,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我需要创建一个报告,我正在努力使用SQL脚本。 我要查询的表是一个公司\状态\历史记录表,其中包含如下条目(我无法理解的条目) 表公司状况历史 栏目: | id | company_id | status_id | effective_date | 数据: 我想回答以下问题:“获取所有在2017年1月1日至2017年12月31日期间至少处于状态1的公司” 以上是我不知道如何处理的情况,因为我需要添加一些类型的逻辑: “如果此行状态为1且其日期在日期范围之前,请检查下一行的日期是否在日期范围内

我需要创建一个报告,我正在努力使用SQL脚本。 我要查询的表是一个公司\状态\历史记录表,其中包含如下条目(我无法理解的条目)

表公司状况历史 栏目:

| id | company_id | status_id | effective_date |
数据:

我想回答以下问题:“获取所有在2017年1月1日至2017年12月31日期间至少处于状态1的公司”

以上是我不知道如何处理的情况,因为我需要添加一些类型的逻辑:

  • “如果此行状态为1且其日期在日期范围之前,请检查下一行的日期是否在日期范围内。”
  • “如果此行的状态为1,且其日期在日期范围之后,请在该行之前检查其日期是否在日期范围之内。”

    • 试试这个,不言自明。回答您问题的这一部分:

      我想回答一个问题:“让所有的公司都参与进来。” 2017年1月1日期间状态1中的某个点的最小值- 2017年12月31日”

    • 如果您希望查找在任何时刻处于状态1且在请求的时间段内有记录的id:
    • 您希望在状态1和期间内查找id的情况:

    • 试试这个,不言自明。回答您问题的这一部分:

      我想回答一个问题:“让所有的公司都参与进来。” 2017年1月1日期间状态1中的某个点的最小值- 2017年12月31日”

    • 如果您希望查找在任何时刻处于状态1且在请求的时间段内有记录的id:
    • 您希望在状态1和期间内查找id的情况:

    • 也许这就是你要找的?对于这类问题,您需要连接表的两个实例,在本例中,我只是通过Id连接下一个记录,这可能并不完全正确。为了做得更好,您可以使用一个窗口函数(如row_number)创建一个新Id,并根据您的需求标准对表进行排序

      如果此行状态为1且其日期在日期范围检查之前 如果下一行的日期在日期范围内,则显示下一行

      declare@range\u st date='2017-01-01'
      声明日期为“2017-12-31”
      挑选
      案例
      
      当csh1.status\u id=1和csh1.effective\u date时,可能这就是您要找的?对于这类问题,您需要连接表的两个实例,在本例中,我只是通过Id连接下一个记录,这可能并不完全正确。为了做得更好,您可以使用一个窗口函数(如row_number)创建一个新Id,并根据您的需求标准对表进行排序

      如果此行状态为1且其日期在日期范围检查之前 如果下一行的日期在日期范围内,则显示下一行

      declare@range\u st date='2017-01-01'
      声明日期为“2017-12-31”
      挑选
      案例
      
      当csh1.status\u id=1和csh1.effective\u date时,我建议使用cte和窗口函数行号。有了它,您可以找到所需的记录。例如:

      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
      
      DECLARE@t表(
      id INT
      ,company_id INT
      ,status_id INT
      ,生效日期日期时间
      )
      插入到@t值中
      (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')
      声明@StartDate DATETIME='2017-01-01';
      声明@EndDate DATETIME='2017-12-31';
      以cte为例(
      挑选*
      ,第()行(按公司id顺序按生效日期划分)为rn
      来自@t
      ),
      cteLeadLag AS(
      选择c.*,ISNULL(c2.生效日期,c.生效日期)LagEffect,ISNULL(c3.生效日期,c.生效日期)LeadEffect
      来自cte c
      在c2.company_id=c.company_id和c2.rn=c.rn-1上左连接cte c2
      在c3.company_id=c.company_id和c3.rn=c.rn+1上左连接cte c3
      )
      选择“包含”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      以及@StartDate和@EndDate之间的生效日期
      联合所有
      选择“以下”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      和生效日期>@EndDate
      并且在@StartDate和@EndDate之间有效
      联合所有
      选择“跟踪”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      和生效日期<@EndDate
      在@StartDate和@EndDate之间生效
      

      我首先选择所有记录及其领先和滞后日期,然后在所需的时间跨度内对其进行检查。

      我建议使用cte和窗口功能行号。有了它,您可以找到所需的记录。例如:

      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
      
      DECLARE@t表(
      id INT
      ,company_id INT
      ,status_id INT
      ,生效日期日期时间
      )
      插入到@t值中
      (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')
      声明@StartDate DATETIME='2017-01-01';
      声明@EndDate DATETIME='2017-12-31';
      以cte为例(
      挑选*
      ,第()行(按公司id顺序按生效日期划分)为rn
      来自@t
      ),
      cteLeadLag AS(
      选择c.*,ISNULL(c2.生效日期,c.生效日期)LagEffect,ISNULL(c3.生效日期,c.生效日期)LeadEffect
      来自cte c
      在c2.company_id=c.company_id和c2.rn=c.rn-1上左连接cte c2
      在c3.company_id=c.company_id和c3.rn=c.rn+1上左连接cte c3
      )
      选择“包含”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      以及@StartDate和@EndDate之间的生效日期
      联合所有
      选择“以下”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      和生效日期>@EndDate
      并且在@StartDate和@EndDate之间有效
      联合所有
      选择“跟踪”作为范围状态*
      来自cteLeadLag
      其中status_id=1
      和生效日期<@EndDate
      在@StartDate和@EndDate之间生效
      
      我首先选择所有记录及其前导和la
           SELECT *
      FROM company_status_history
      WHERE status_id=1
        AND effective_date BETWEEN '2017-01-01' AND '2017-12-31'
      
      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
      
      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
      
      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
      
      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
      
      ;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
      
      ;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