开发者

Is it possible to condense these queries into one?

I have two tables, with one containing records referencing the other:

Goal
  id (int)
  name (text)
  value_mask (text)

GoalStatus
  id (int)
  goal (int)
  created (datetime)
  value (text)

Goal.id == GoalStatus.goal

What I'd like 开发者_C百科to do, is pull the latest record from the GoalStatus table, for each record in Goal. At the moment the only way I know how to do this is by making a separate query for each record in Goal (pseudocode):

goals = db.query("SELECT * FROM Goal")

foreach (goals as goal):
    goalStatus = db.query("
        SELECT * FROM GoalStatus
        WHERE goal = " + goal.id + "
        ORDER BY created DESC
        LIMIT 1
    ")

Is there a way of condensing this, so I'm not making an extra query for each Goal?


This is the per-group-maximum question. It's a very common thing to want to do that SQL doesn't make easy, so it gets asked a lot.

Here's a summary of approaches you can take. They'll have different performance attributes, and can behave differently when there are two rows sharing the same value as the maximum.

As a default first approach I would tend to go for a null-left-join rather than a subquery:

SELECT ...
FROM Goal
JOIN GoalStatus AS Gs0 ON Gs0.goal=Goal.id
LEFT JOIN GoalStatus AS Gs1 ON Gs1.goal=Goal.id AND Gs1.created>Gs0.created
WHERE Goal.id=(someid)
AND Gs1.id IS NULL

that is to say, join rows where there is no other row that has a greater created value.


select 
      g.*,
      gs.id GoalStatusID,
      gs.created,
      gs.value
   from 
      goal g inner join goalstatus gs
          on g.id = gs.goal
   where 
      gs.created in 
          ( select max( gs2.created )
               from goalstatus gs2
               where g.id = gs2.goal )


You could join on GoalStatus where there is no other goal status with the same goal id that has a greater created date.

SELECT * 
FROM Goal 
    INNER JOIN GoalStatus on Goal.GoalId=GoalStatus.GoalId 
WHERE Not Exists(SELECT * 
                 FROM GoalStatus innerGs 
                 WHERE innerGs.GoalId=Goal.GoalId 
                     and innerGs.created > GoalStatus.created)

Pretty ugly and will probably perform poorly but all I could think of.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜