Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从同一sql表中获取不同列的最新值和最早值_Sql_Sql Server_Group By_Self Join_Having - Fatal编程技术网

从同一sql表中获取不同列的最新值和最早值

从同一sql表中获取不同列的最新值和最早值,sql,sql-server,group-by,self-join,having,Sql,Sql Server,Group By,Self Join,Having,我有一张可以选择日期的桌子。我希望能够应用WHERE语句返回一组数据,然后从一列返回最早的日期,从另一列返回最晚的日期。下面是一个示例表: ID StartDate EndDate Person Subject 1 01/03/2010 03/03/2010 Paul Math 2 12/05/2010 22/05/2010 Steve Science 3 04/03/2010 08/03/2010 Paul English 所以

我有一张可以选择日期的桌子。我希望能够应用WHERE语句返回一组数据,然后从一列返回最早的日期,从另一列返回最晚的日期。下面是一个示例表:

ID  StartDate   EndDate     Person   Subject
1   01/03/2010  03/03/2010   Paul    Math
2   12/05/2010  22/05/2010   Steve   Science
3   04/03/2010  08/03/2010   Paul    English

所以我想返回Person='Paul'的所有记录。但是返回类似于(最早的)StartDate=01/03/2010(来自记录ID 1)和(最晚的)EndDate=08/03/2010(来自记录ID 3)和Subject=English(来自记录3)。我需要两行Paul和上面的数据和Id。需要person='Paul'的所有行

预期结果:

ID  StartDate   EndDate Person  Subject
1   2010-03-01  2010-03-08  Paul    English
3   2010-03-01  2010-03-08  Paul    English
在下面的sql查询中,您是否发现与性能(数百万条记录)有关的任何问题:

 Select PT3.ID,PT4.EarliestStartDate AS StartDate,PT4.EndDate,PT4.Person,PT4.Subject from Data AS PT3 
Join( SELECT Top 1 with ties * FROM Data AS PT  
Join( SELECT PT1.Person as Person1, MIN(PT1.StartDate ) as EarliestStartDate FROM Data AS PT1 where Person ='Paul' group by PT1.Person)  AS PT2 ON  PT.Person =PT2.Person1WHERE Person  ='Paul'
  Order By Row_Number() over (Partition By PT.Person Order By PT.EndDate desc)) AS PT4 ON PT3.Person = PT4.Person 
这可能会起作用:

  • 首先执行
    分组
    ,以获取每个人所需的日期
  • 将分组移动到公共表表达式(
    cte
  • 使用完整数据集连接回以获取所有行
  • 对于每个结果记录,使用交叉应用选择相应的主题
  • 可选:筛选所需人员(
    where
    子句)
  • 样本数据

    create table Data
    (
      ID int,
      StartDate date,
      EndDate date,
      Person nvarchar(10),
      Subject nvarchar(10)
    );
    
    insert into Data (ID, StartDate, EndDate, Person, Subject) values
    (1, '2010-03-01', '2010-03-03', 'Paul',  'Math'),
    (2, '2010-05-12', '2010-05-22', 'Steve', 'Science'),
    (3, '2010-03-04', '2010-03-08', 'Paul',  'English');
    
    解决方案

    with cte as
    (
      select min(d.StartDate) as StartDate,
             max(d.EndDate) as EndDate,
             d.Person
      from Data d
      group by d.Person
    )
    select d.Id,
           c.StartDate,
           c.EndDate,
           c.Person,
           x.Subject
    from cte c
    join data d
      on d.Person = c.Person
    cross apply ( select top 1 d2.Subject
                  from Data d2
                  where d2.Person = c.Person
                    and d2.EndDate = c.EndDate ) x
    where d.Person = 'Paul'
    order by d.Person;
    

    查看它的运行情况。

    这将为您提供正确的值

    DECLARE @values TABLE (
        Id INT,
        StartDate DATETIME2,
        EndDate DATETIME2,
        Person NVARCHAR(MAX),
        Subject NVARCHAR(MAX))
    
    INSERT INTO @values VALUES 
    (1, '2010-03-01', '2010-03-03', 'Paul', 'Math'),
    (2, '2010-05-12', '2010-05-22', 'Steve', 'Science'),
    (3, '2101-03-04', '2010-03-08', 'Paul', 'English')
    
    ;WITH sort AS (
        SELECT
            Person,
            MIN(StartDate) OVER(PARTITION BY Person) StartDate,
            MAX(EndDate) OVER(PARTITION BY Person) EndDate,
            Subject,
            ROW_NUMBER() OVER(PARTITION BY Person ORDER BY EndDate DESC) rownum
        FROM @values v)
    
    SELECT
        Person,
        StartDate,
        EndDate,
        Subject
    FROM sort
    WHERE rownum = 1
    
    它将为您提供以下结果:

    Person  MinStartDate    MaxEndDate   Subject
    Paul    2010-03-01      2010-03-08   English
    Steve   2010-05-12      2010-05-22   Science
    

    如果您只关心选择Pauls数据,这就足够了:

    SELECT 
       Person,
       MIN(startDate) AS Earliest, 
       MAX(EndDate) AS Latest, 
       (
          SELECT TOP 1 Subject 
          FROM Data
          WHERE Person = 'Paul'
          ORDER BY EndDate DESC
       ) AS Subject
    FROM Data WHERE Person = 'Paul'
    
    如果要选择所有人员,则此操作应有效:

    SELECT 
       d1.Person,
       MIN(d1.startDate) AS Earliest, 
       MAX(d1.EndDate) AS Latest, 
       (
          SELECT TOP 1 d2.Subject 
          FROM Data d2
          WHERE d2.Person = d1.Person
          ORDER BY EndDate DESC
       ) AS Subject
    FROM Data d1
    GROUP BY d1.Person
    
    编辑:您似乎希望表中的每一行都有结果,而不是每人一行,但始终显示最早和最晚的日期。这就是你想要的吗

    SELECT 
       d1.Id,
       d1.Person,
       (
          SELECT MIN(d1.StartDate) AS Earliest
          FROM Data d2
          WHERE d2.Person = d1.Person
       ) AS Earliest,
       (
          SELECT MAX(d1.EndDate) AS Latest
          FROM Data d2
          WHERE d2.Person = d1.Person
       ) AS Latest,
       (
          SELECT TOP 1 d2.Subject 
          FROM Data d2
          WHERE d2.Person = d1.Person
          ORDER BY EndDate DESC
       ) AS Subject
    FROM Data d1
    

    请显示您的查询声音,如“分组依据”和“最小/最大”。因此,您希望获得最早的开始日期和最新的结束日期,而不考虑主题?然后分别获取最新结束日期的主题?预期结果是什么?需要person='Paul'的所有行您当前的版本无法解决问题的
    主题
    部分。@Kristofer我如何才能在查询的相同结果集中获得Paul的所有Id(其他列值将相同)?您的答案不包含有效的SQL语法(提示:文本字符串
    Paul
    需要引号)。@Sander我修复了它,并将Person列添加到result@Fuzzy我已经用预期结果更新了问题我已经添加了预期结果和我的查询