views:

77

answers:

5

Let's say I have an item table with columns id (PK), parent_id (FK), name, and date. I also have an item_parent table with columns id (PK) and name. Items can belong to the same parent, or an item can have no parent (parent_id can be null).

I am trying to construct a SQL query to select all items ordered by date (DESC), keeping all items that share the same parent together (and in this case, order by the max date of the collection of items).

If it's helpful to know, I'm using SQL Server 2005.

+1  A: 

I think this is what you are looking for, as your question is not very clear:

SELECT *
FROM itemTable
ORDER BY parent_id, date desc

This will select all columns and items from the itemTable, with a primary sort on the parent_id and a secondary order by date oldest date first.

Perhaps you can edit your question and post a sample of input data and the required output, to illustrate exactly what you need?

Oded
I am insulted by this answer.
richard23
@richard23 - why are you insulted by this answer? Stackoverflow is a forum for developers of _all_ levels, and perhaps you need to establish in your question what level of answer you are looking for. I always try to explain my answers so as many people as possible understand the solution/answer.
Oded
A: 

You can use ORDER BY on several columns at once:

SELECT *
FROM itemtable
ORDER BY parentID, Date DESC

Is that what you're looking for?

Raven Dreamer
This will not keep all identical parent_ids together.
Oded
@Oded, that's what ORDER BY does. Why do you believe that this would not keep all identical parent_ids together?
Philip Kelley
@Philip Kelley - before the edit it was `ORDER BY Date desc, parentID`
Oded
Yeah, I misread the question at first, had the priority swapped. Thanks for pointing that out, Oded. :)
Raven Dreamer
A: 

Since the date you want to sort on is the max date within the group of items for a single parent, the implication is that the items must be sorted first by that date and then, (in the edge case where multiple items with different parents happen to share the same max date), then, within the group defined by the same date secondly, sort by the parent within that group with the same date.

Try this:

   Select i.*
   From item i 
      Left Join item_parent p 
          On p.id = i.parentId
   Order By 
       (Select Max(date) From items
        Where IsNull(parentId,0) = isNull(i.ParentID, 0)) DESC, 
        i.ParentId, i.Date DESC

all the items with no parent will show up together
EDIT: (to fold all items with null parent into the same ordering list...)
2ND EDIT: Just add DESC to Order By -- No offense but you should have seen this!
3RD EDIT: now also sorted within each parent group by actual item date DESC

Charles Bretana
This works but I don't want items without a parent to be separated from items with a parent (giving 2 individual sorted lists). I want them both integrated. Can it be modified to achieve this?
richard23
Yes, I think as I have edited it will work...
Charles Bretana
With the following change to your WHERE clause (on the inner SELECT within the ORDER BY), this extremely close to perfect:WHERE ISNULL(Parent_ID, Item_ID) = ISNULL(I.Parent_ID, I.Item_ID)The one outstanding issue is that a collection of items from a given parent is not always sorted by date DESC.
richard23
@Charles, any thoughts on how to resolve this issue? Items with a parent (while properly "grouped" together) are not always ordered by date DESC.
richard23
@richard23, Edited again to sort DESC. no offense, but you should have seen this. Are you new to SQL?
Charles Bretana
@Charles, That doesn't work. I already tried it.
richard23
@Charles, Overall the dates are in descending order (correct). However, within a set of items having the same parent, the dates are not always in descending order.
richard23
@richard, within a set of items having the same parent, the MAX(Date) should always be the SAME DATE... Are you also trying to also order the individual items WITHIN a single parent group by the ACTUAL DATE of the item ?? i.e. do you want TWO sorts, one by the max date of the collection, and another by the actual date of the individual item?
Charles Bretana
@Charles, Yes, that is exactly what I am trying to achieve.
richard23
@Charles, Thank you!
richard23
A: 

If you actually want to group by parent_id for those rows that have it defined, then you could use:

select id, parent_id, MAX(date) AS date
from itemTable
group by parent_id, coalesce(parent_id, id)
order by MAX(date) desc

The coalesce allows us to group on ID (i.e. no grouping) only when parent_id is null.

ar
I don't want to group by parent_id. I want to get the parent_id and all individual child items belonging to it.
richard23
A: 

You have a bit of contradiction in how you want to order your items:

select all items ordered by date (DESC), keeping all items that share the same parent together (and in this case, order by the max date of the collection of items).

Does that mean first by parent and then, within a given parent, by date or do you want it first by date and then by parent which means you probably will not get items with the same parent listed together. I assumed the former:

Select I.id, I.parent_id, I.name, I.date
From item As I
    Left Join item As P
        On P.id = I.parent_id
    Outer Apply (
                Select Max(I2.date) As [Date]
                From item As I2
                Where I2.Id = I.parent_id
                ) As MaxDate
Order By I.parent_Id, MaxDate.[Date] Desc, I.Date Desc

If you did not care to return any data from the parent of a given item, then you can eliminate the left join:

Select I.id, I.parent_id, I.name, I.date
From item As I
    Outer Apply (
                Select Max(I2.date) As [Date]
                From item As I2
                Where I2.Id = I.parent_id
                ) As MaxDate
Order By I.parent_Id, MaxDate.[Date] Desc, I.Date Desc
Thomas
This gives the following error: "An aggregate cannot appear in an ON clause unless it is in a subquery contained in a HAVING clause or select list, and the column being aggregated is an outer reference." Also, I1 is not defined, did you mean I?
richard23
Also, what you assumed (the former) is correct.
richard23
@richard23 - I believe both problems are due to a typo in the Outer Apply query. I've corrected my post.
Thomas
You are selecting from item and left joining item. I believe you intended to left join item_parent as alias P. Assuming this is correct, the result set lists all of the items without a parent ordered by date, then items with a parent ordered by date below (2 ordered lists, one on top of the other). I want them to be integrated.
richard23
@richard23 - RE: left joining, I'm assuming that item.parent_id is a FK to item.id. Thus, the left join should be correct as I've written it. In fact, if you do not want to return any column from the parent, you can remove the Left Join entirely. RE: "integrated", what exactly do mean by "integrated"? Forget sorting for a moment, at the end of the day, you are returning data directly from a single table. Some rows have a null parent_id and some have a non-null parent_id. Can you show us some sample data and sample output?
Thomas
@Thomas, since the date he wants to sort on is the max date within the group of items for a single parent, the implication is that the items must be sorted first by that date and then, within the group defined by the same date (in the edge case where multiple items with different parents happen to share the same max date), then secondly, by the parent within the group with the same date
Charles Bretana
@Thomas, item.parent_id is a FK to item_parent.id, not item.id. It's not a self-referencing relationship.
richard23
@richard23 - You should clarify that in your OP (along with providing sample input and output data). What is the parent table to parent_id? Typically, a column given the vague name of "parent_id" implies a self-join.
Thomas
@richard23, @Charles Bretana - Can you confirm whether Charles Bretana's response is what you are seeking? If it is, then the solution is simple: change the order by to `MaxDate.[Date] Desc, I.[Date] Desc` (i.e. remove I.parent_id).
Thomas
@Thomas, Charles' solution is the closest so far. There's still an issue with date ordering for items with a parent though. Your solution gives duplicate records if an item has a parent.
richard23
@richard2 - That isn't possible in the second solution as I'm only pulling from a single table.
Thomas