views:

33

answers:

2

I'm trying to turn this query into a view:

SELECT t.*
 FROM user t
 JOIN (SELECT t.UserId, 
              MAX( t.creationDate ) 'max_date'
         FROM user t
     GROUP BY t.UserId) x ON x.UserId = t.UserId
                         AND x.max_date = t.creationDate

But views do not accept subqueries.

What this does is look for the latest, newest record of a user. I got the idea from this other stackoverflow question

Is there a way to turn this into a query with joins, perhaps?

+2  A: 

Create two views

 Create View MaxCreationDate
 As
      SELECT t.userId, Max(t2.CreationDate) MaxCreated
      FROM user t 
      Group By t.UserId

Create View UserWithMaxDate
As
      Select t.*, m.MaxCreated From user t
         Join MaxCreationDate m
             On m.UserId= t.UserId

and then just call the second one...

EDIT: hey, based on comment from Quassnoi, and your inclusion of where t.CreationDate = MaxDate in yr orig sql, I wonder if you want to see all rows for each distinct user, with the max creation date for that user in every row, or, do you want only one row per user, the one row that was created most recently?

If the latter is the case, as @Quassnoi suggested in comment, change the second view query as follows

Create View UserWithMaxDate
As
      Select t.*, m.MaxCreated From user t
         Join MaxCreationDate m
             On m.UserId= t.UserId
                 And m.MaxCreated = t.Creationdate
Charles Bretana
Abandoning my answer after seeing yours.
JungleFreak
Not a recommended practice, layering views on top of one another. If the foundation view changes, there won't be errors until the children view statements are executed. Also promotes view reuse rather than optimal query design, depending on what the view queries are doing...
OMG Ponies
@OMG Ponies, I agree, but could not think of another approach that would resolve his issue... Can you?
Charles Bretana
@Charles: you need to add `m.maxcreated = t.creationDate` into your second view and replace `LEFT JOIN` with an `INNER JOIN`. `LEFT JOIN` with a view on the nullable side is a real performance killer.
Quassnoi
My first instinct is to use PostgreSQL, Oracle or SQL Server. MySQL really needs to catchup in functionality.
OMG Ponies
@OMGPonies: wait until you will need to perform a massive update on a heavily indexed table in `PG`.
Quassnoi
@Quassnoi, 1) I think he wants to see a separate row in output for each user, and your mod would restrict the output to only one row per creation date... 2) re: outer joins in Views: I did not know that... It has been my policy to avoid views like the plague (I will generally opt for a Stored proc before I use one ), so thanks for this tidbit!
Charles Bretana
@Charles: your current query is not the same as the @op's example. @op's query returns one record per `userid`, your query returns all records. Actually, your query just replaces the inline view `x` in the op's query with an explicit view, and omits the `x.max_date = t.creationDate` part. `LEFT JOIN` is just redundant here: on both sides, it's impossible to have a `userid` that is not already in the table.
Quassnoi
@Quassnoi, yes I wondered about that, but thought it was an unintentional error.. If all he wants is the latest creation date, then he just needs one Group By query with a max(CreationDate) I am editing my answer to address both possibilities
Charles Bretana
+1  A: 
CREATE INDEX ix_user_userid_creationdate_id ON user (userid, creationdate, id);

CREATE VIEW v_duser AS
SELECT  DISTINCT userId
FROM    user;

CREATE VIEW v_lastuser AS
SELECT  u.*
FROM    v_duser ud
JOIN    user u
ON      u.id =
        (
        SELECT  ui.id
        FROM    user ui
        WHERE   ui.userid = ud.userid
        ORDER BY
                ui.userid DESC, ui.creationdate DESC, ui.id DESC
        LIMIT 1
        );

This is fast and deals with possible duplicates on (userid, creationdate).

Quassnoi