TSQL Select Max - PullRequest
       2

TSQL Select Max

4 голосов
/ 15 июля 2010
Userid   FirstName   LastName        UserUpdate 
1        Dan         Kramer          1/1/2005  
1        Dan         Kramer          1/1/2007  
1        Dan         Kramer          1/1/2009  
2        Pamella     Slattery        1/1/2005  
2        Pam         Slattery        1/1/2006  
2        Pam         Slattery        1/1/2008  
3        Samamantha  Cohen           1/1/2008  
3        Sam         Cohen           1/1/2009  

Мне нужно извлечь последние обновления для всех этих пользователей, в основном вот что я ищу:

Userid   FirstName   LastName        UserUpdate  
1        Dan         Kramer          1/1/2009     
2        Pam         Slattery        1/1/2008   
3        Sam         Cohen           1/1/2009  

Теперь, когда я запускаю следующее:

ВЫБЕРИТЕ ИД пользователя, Имя, Фамилия, Макс (UserUpdate) AS MaxDate С таблицы GROUP BY Идентификатор пользователя, Имя, Фамилия

Я все еще получаю дубликаты, что-то вроде этого:

Userid   FirstName   LastName        UserUpdate 
1        Dan         Kramer          1/1/2009  
2        Pamella     Slattery        1/1/2005  
2        Pam         Slattery        1/1/2008  
3        Samamantha  Cohen           1/1/2008  
3        Sam         Cohen           1/1/2009 

Ответы [ 4 ]

4 голосов
/ 15 июля 2010

попробовать:

declare @Table table (userid int,firstname varchar(10),lastname varchar(20), userupdate datetime)
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2005')  
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2007')  
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2009')  
INSERT @Table VALUES (2, 'Pamella'     ,'Slattery'        ,'1/1/2005')  
INSERT @Table VALUES (2, 'Pam'         ,'Slattery'        ,'1/1/2006')  
INSERT @Table VALUES (2, 'Pam'         ,'Slattery'        ,'1/1/2008')  
INSERT @Table VALUES (3, 'Samamantha'  ,'Cohen'           ,'1/1/2008')
INSERT @Table VALUES (3, 'Sam'         ,'Cohen'           ,'1/1/2009') 

SELECT
    dt.Userid,dt.MaxDate
        ,MIN(a.FirstName) AS FirstName, MIN(a.LastName) AS LastName
    FROM (SELECT 
              Userid, Max(UserUpdate) AS MaxDate 
              FROM @Table GROUP BY Userid
         ) dt
        INNER JOIN @Table a ON dt.Userid=a.Userid and dt.MaxDate =a.UserUpdate
    GROUP BY dt.Userid,dt.MaxDate

ВЫХОД:

Userid      MaxDate                 FirstName  LastName
----------- ----------------------- ---------- --------------------
1           2009-01-01 00:00:00.000 Dan        Kramer
2           2008-01-01 00:00:00.000 Pam        Slattery
3           2009-01-01 00:00:00.000 Sam        Cohen
3 голосов
/ 15 июля 2010

Вы не получаете дубликаты. 'Pam' не равно 'Pamella' с точки зрения базы данных; тот факт, что одно является разговорным сокращением другого, ничего не значит для движка базы данных. На самом деле не существует надежного универсального способа сделать это (поскольку существуют имена, которые имеют несколько сокращений, например, «Роб» или «Боб» для «Роберт», а также сокращения, которые могут подходить для нескольких имен, таких как «Кел» для «Келли» "или" Келси ", пусть один тот факт, что имена могут иметь альтернативные варианты написания).

Для вашего простого примера вы можете просто выбрать и сгруппировать SUBSTRING(FirstName, 1, 3) вместо FirstName, но это просто совпадение, основанное на ваших данных выборки; другие сокращения имени не соответствуют этому шаблону.

1 голос
/ 16 июля 2010

Или используйте подзапрос ...

SELECT
   a.userID,
   a.FirstName,
   a.LastName,
   b.MaxDate
FROM
      myTable a
   INNER JOIN
      (   SELECT
             UserID,
             Max(ISNULL(UserUpdate,GETDATE())) as MaxDate
          FROM
             myTable
          GROUP BY
             UserID
      ) b
   ON
          a.UserID = b.UserID
      AND a.UserUpdate = b.MaxDate

Подзапрос (с именем "b") возвращает следующее:

Userid   UserUpdate  
1        1/1/2009     
2        1/1/2008   
3        1/1/2009 

INNER JOIN между подзапросом и исходной таблицейприводит к тому, что исходная таблица фильтруется только для совпадающих записей - т. е. будут возвращены только записи с парой UserID / UserUpdate, которая соответствует паре UserID / MaxDate из подзапроса, что даст вам недублированный набор результатов, который вы искали:

Userid   FirstName   LastName        UserUpdate  
1        Dan         Kramer          1/1/2009     
2        Pam         Slattery        1/1/2008   
3        Sam         Cohen           1/1/2009  

Конечно, это всего лишь обходной путь.Если вы действительно хотите решить проблему в долгосрочной перспективе, вам следует нормализовать исходную таблицу, разделив ее на две части.

Table1:

Userid   FirstName   LastName 
1        Dan         Kramer   
2        Pam         Slattery 
3        Sam         Cohen

Table2:

Userid   UserUpdate  
1        1/1/2007     
2        1/1/2007   
3        1/1/2007  
1        1/1/2008     
2        1/1/2008   
3        1/1/2008 
1        1/1/2009     
2        1/1/2009   
3        1/1/2009 

Это был бы более стандартный способ хранения данных, и его было бы намного проще запрашивать (не прибегая к подзапросу).В этом случае запрос будет выглядеть так:

SELECT
   T1.UserID,
   T1.FirstName,
   T1.LastName,
   MAX(ISNULL(T2.UserUpdate,GETDATE()))
FROM
      Table1 T1
   LEFT JOIN
      Table2 T2
   ON
      T1.UserID = T2.UserID
GROUP BY
   T1.UserID,
   T1.FirstName,
   T1.LastName
0 голосов
/ 31 января 2011

Другой вариант, если у вас есть SQL 2005 (я думаю?) Или более поздняя версия, будет использовать общее табличное выражение и вытащить из таблицы идентификатор пользователя и максимальную дату, а затем соединиться, чтобы получить совпадающие имя и фамилию в максимальная дата ПРИМЕЧАНИЕ. При этом предполагается, что идентификатор пользователя + дата всегда будет уникальным, запрос будет прерван, если вы получите 2 строки с одинаковыми идентификатором пользователя и датой. Как уже отмечали другие, это довольно ужасный дизайн базы данных - но иногда это жизнь, проблема все равно должна быть решена. например,

declare @Table table (userid int,firstname varchar(10),lastname varchar(20), userupdate datetime) 
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2005')   
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2007')   
INSERT @Table VALUES (1, 'Dan'         ,'Kramer'          ,'1/1/2009')   
INSERT @Table VALUES (2, 'Pamella'     ,'Slattery'        ,'1/1/2005')  
INSERT @Table VALUES (2, 'Pam'         ,'Slattery'        ,'1/1/2006')   
INSERT @Table VALUES (2, 'Pam'         ,'Slattery'        ,'1/1/2008')   
INSERT @Table VALUES (3, 'Samamantha'  ,'Cohen'           ,'1/1/2008') 
INSERT @Table VALUES (3, 'Sam'         ,'Cohen'           ,'1/1/2009'); 



with cte ( userid , maxdt ) as 
    (select userid, 
            max(userupdate) 
    from @table 
    group by userid)


SELECT  dt.Userid,
        dt.firstname,
        dt.lastname,
        cte.maxdt

FROM    
    @Table dt
    join cte on cte.userid = dt.userid and dt.userupdate = cte.maxdt

выход

Userid      firstname  lastname             maxdt
----------- ---------- -------------------- -----------------------
3           Sam        Cohen                2009-01-01 00:00:00.000
2           Pam        Slattery             2008-01-01 00:00:00.000
1           Dan        Kramer               2009-01-01 00:00:00.000
...