开发者

SQL Group By and Join

I feel totally stupid. I'm rusty with my sql.

I have two tables, Message and MessageThread. Each message belongs to one MessageThread using ParentTHreadID as a Foreign Key. You probably can see where this is going.

Well, I want to do something like this. I want to get columns from both tables, messages and threads, but where the message's datecreated is th开发者_运维问答e maximum in that thread. So each record will contain the thread columns and the columns for one message record that is the most recent posted in that message thread.

Here is what I have so far which gets me all the thread columns and the ID of the message. It works, but uses a subquery and I'd have to make a bunch of other subqueries to get the other columns. Yuck.

select t.*, (select top 1 m.ID from Message m where m.ParentThreadID = t.ID order by DateCreated desc ) as MessageID

from MessageThread t

Bonus points to anyone who can not only give me sql, but linq to sql or linq to nhibernate.

Thanks, Craig


The solution: more subqueries!!

  select * from (
    select t.*, (
      select top 1 ID 
      from Message 
      where ParentThreadID = t.ID 
      order by DateCreated desc 
    ) as MessageID
    from MessageThread t
  ) tm
  left join Message m on tm.MessageID = m.ID 

This should get you all the columns with two nested queries.


How would this work for you:

SELECT (whateverYouWant)
FROM Message m, MessageThread mt
WHERE m.ParentThreadID = mt.ID
AND mt.DateCreated = (SELECT MAX(mt2.DateCreated) 
                      FROM MessageThread mt2 
                      WHERE mt2.ID= mt.ID)

This has the effect of selecting only one row, the one which has the maximum date for that thread. Also, it means that you can select whichever columns you want without having to subquery them which reduces the number of table scans or index scans your query has to do.


First, you can write this without a derived table (as in your OP) by using a subquery like so:

Select ...
From MessageThread As T
Where Id = (
            Select TOP 1 M.Id
            From Message As M
            Where M.ParentThreadId = T.Id
            Order By DateCreated Desc
            )

The equivalent LINQ would be something like:

    var query = from messageThread in MessageThread
                join message in Message on message.ParentThreadId == messageThread.Id
                let first = ( messages.Where( m => m.ParentThreadId == messageThread.Id ).OrderByDescendng(m => m.DateCreated).First().Id )
                where messageThread.Id == first
                select new {MessageThread = messageThread, Message = Message};

EDIT You mentioned that you need the data from Message as well. In which case, simply join to Message.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜