2015-04-16 15 views
6

ho tavolo con tale strutturaSemplificare SQL SELECT

CREATE TABLE UsersHistory 
(
    Id   INT IDENTITY, 
    UserID  INT, 
    StatusId INT, 
    CreateTime DATETIME, 
    ChangedTime DATETIME 
) 

INSERT INTO UsersHistory(UserID, StatusId, CreateTime, ChangedTime) 
SELECT 1,1,'20150414','20150414' UNION ALL 
SELECT 1,2,'20150414','20150415' UNION ALL 
SELECT 1,3,'20150414','20150416' UNION ALL 
SELECT 2,1,'20150413','20150413' UNION ALL 
SELECT 2,3,'20150413','20150416' 

e interrogazione

;WITH k AS (
SELECT uh.UserID,MAX(uh.ChangedTime) AS Dt FROM UsersHistory AS uh 
WHERE uh.ChangedTime<'20150416' 
GROUP BY uh.UserID 
) 
SELECT k.UserID,uh.StatusId FROM k 
INNER JOIN UsersHistory AS uh 
    ON k.UserID = uh.UserID AND k.Dt = uh.ChangedTime 

query è troppo facile e non necessita di ulteriori spiegazioni. Voglio semplificarlo. (Rimuovi join con colonna tipo datetime).

Qualche suggerimento?

risposta

1

È possibile utilizzare ROW_NUMBER() con PARTITION per raggiungere questo obiettivo. Qualcosa di simile

;WITH CTE as 
( 
    SELECT UserID, StatusId, CreateTime, ChangedTime,ROW_NUMBER()OVER(PARTITION BY UserID ORDER BY ChangedTime DESC) r 
    FROM UsersHistory 
    WHERE ChangedTime < '20150416' 
) 
SELECT UserID, StatusId FROM CTE 
WHERE r = 1 
+1

Questo è ovviamente il vincitore. Le domande non necessariamente complicate portano a volte a risposte non facilmente complicate. È un buon talento vedere la semplicità in questi casi. –

0

In SQL Server 2012+, è possibile utilizzare first_value():

SELECT uh.UserID, 
     FIRST_VALUE(uh.StatusId) OVER (PARTITION BY uh.UserId ORDER BY ChangedTIme DESC) 
     MAX(uh.ChangedTime) AS Dt 
FROM UsersHistory AS uh 
WHERE uh.ChangedTime < '20150416'; 
0

Mi pare di capire che si desidera selezionare l'ID utente e StatusId dei record con la massima ChangedTime dove ChangedTime non è uguale a '20.150.416'. Si prega, Prova questa ricerca:

SELECT 
    uh.UserId, uh.StatusId 
    FROM UsersHistory AS uh 
    WHERE uh.ChangedTime<'20150416' 
    AND uh.ChangedTime=(SELECT MAX(ChangedTime) FROM UsersHistory 
              WHERE UserId=uh.UserId); 
0

È possibile aggiungere sottoquery nella clausola WHERE. Qualcosa del genere:

SELECT uh.UserID, 
     MAX(uh.ChangedTime) AS Dt, 
     uh.StatusId 
FROM UsersHistory uh 
WHERE uh.ChangedTime < '20150416' 
     AND uh.ChangedTime= 
         (
         SELECT MAX(ChangedTime) 
         FROM UsersHistory 
         WHERE UserId=uh.UserId 
         ) 
GROUP BY uh.UserID, uh.StatusId 
+0

Si sta raggruppando per userid e si seleziona statusid senza aggregazione. È un errore di sintassi. –

+0

Grazie per la correzione, persa, risolto. –

0

Con APPLY:

Select uh1.UserID, oa.StatusID 
From UserHistory uh1 
Cross Apply(Select * From (Select Top 1 uh2.StatusID, uh2.Changetime 
      From UserHistory uh2 
      Where uh2.UserID = uh1.UserID And uh2.Changetime < '20150416' 
      Order By uh2.Changetime desc) t where t.Changetime = uh1.Changetime) oa 
0
SELECT 
    distinct uh.UserID, 
    statusid 
FROM UsersHistory uh 
inner join 
    (select 
     UserID, 
     max(ChangedTime) dt 
    from UsersHistory 
    group by UserID) ct 
on (ct.UserID=uh.userid and ct.dt=uh.ChangedTime)