tags:

views:

37

answers:

3

I have a table which has two keys and I cannot break the table up into two.

The first key, id is a counter. The second key is parent_id.

For example:

id, parent_id, text
1, 0, Hello Steve - this is Bill
2, 1, Hi - how are you Bill?
3, 0, Good morning Janice
4, 3, Hello - good morning to you

The first record is the parent record of the conversation and the second is the child record.

What I'm having difficulty doing is writing a query that returns both records for a single conversation when you pass either id.

For example:

select * from table where id = 2 or parent_id = ( select parent_id from table where id = 2 )
select * from table where id = 1 or parent_id = ( select parent_id from table where id = 1 )

The first query will work, returning the records with id 1 and 2. The second will not as it will return the row with id 3 as well because if you pass 1 you'll get zero for the parent_id.

I'm sure it's something simple that I'm missing due to paralysis by analysis.

Thanks.

+2  A: 

Add AND parent_ID <> 0 to your subquery.

ck
If you do that and pass in the child ID, it omits the parent record and if you pass in a parent ID, it omits the child records.
Tom
+1  A: 
-- I *think* from OP's description , this should do it.
-- The first SELECT will _always_ bring back a single row (the ID is unique and known to the issuer of the query).
-- The second SELECT may bring back zero, one or many rows
-- So (if my understanding is correct) in English:
-- Bring back the row for the given ID and all (if any) rows which have me as a parent_id.
-- Rehashed : joining up the IDs from parent->child
-- Again, not tried...
SELECT * FROM table parent WHERE parent.id = <id>
union
SELECT * FROM table child WHERE child.id=parent.id;
monojohnny
If you want to return the first conversation, records with id 1 and 2, and you pass 1 using the queries in my example, you'll also get 3 back because it has a parent_id of zero as well.
Tom
Understood that (I think) - but is the data-model not going to imply this ? Ultimately do you always want exactly one row returned - or could this vary , depending on the conversation history?
monojohnny
No, ultimately I want the whole conversation returned whether a child or parent ID is passed into the query. My mistake not making that clear in the OP.
Tom
So is a 'conversation' exactly one parent and exactly one child ? (always expect/want two rows back?) I guess (also from an earlier posting answer) - that the main issue here could be that '0' is 'special' - it denotes 'start of conversation....would then the '<>0' bit work (suggested above).If you do need to traverse more than two records, not sure how you would do this without 'CONNECT BY' type arrangements....
monojohnny
No, there could be many child records. Think of it as an article commenting system. One person adds a comment and multiple people can add replies to that comment. It only goes one deep though, users cannot reply to a reply. Basically a user can click reply to a parent comment or a child comment and on the comment page they can review the entire thread so whether a parent ID or child ID is passed, I want to return the entire conversation.
Tom
Hi Tom - just commented on your OP - can you add in a couple more examples of what subsequent records would like ...
monojohnny
Regarding the <> 0 bit, that doesn't work, tried it =)
Tom
I *think* you want a 'UNION' here...not an 'OR' - just edited my answer....
monojohnny
Yeah, that query just returns a child record if you pass a child ID into it. I have a huge union query that works (needs for selects) but there has to be an easier way.
Tom
Just re-hashed that again...still not giving you what you want ? Have you tried P.Cambell's suggestion at all ? (looks like it should do the trick - actually , it beyond my capabilities :-) )
monojohnny
Yeah, that works. Wish there was a cleaner way but I'm thinking there isn't...thanks for the help though monojohnny =)
Tom
( No worries: I know you said you can't change your data model, but probably that would be the 'proper' solution..separating 'post' records and 'reply' records...) anyway - glad you got something that works ! Cheers
monojohnny
+2  A: 

This query will retrieve:

  • the specified child record, its parent, and its siblings
  • the specified parent record and all its single-level children
 SELECT DISTINCT * FROM 
 (
    --is a child of the specified parent
    SELECT * from table  WHERE parent_id = @SomeID 
    UNION ALL
    -- is the record specified by ID
    SELECT * from table  WHERE ID = @SomeID 
                         --and get the parent itself
                         OR ID = (SELECT parent_id FROM table WHERE ID = @SomeID) 

    UNION ALL
    --all siblings with the same parent
    SELECT * FROM table WHERE parent_id = (SELECT parent_id 
                                           FROM table WHERE ID = @SomeID) 
                        AND parent_id>0

   ) F
ORDER BY ID 
p.campbell
I was thinking this needed a 'UNION' as well...I don't think my answer quite covers though....
monojohnny
This works. I wish there was a cleaner way to do it but I can't figure it out and this is a little cleaner than the huge union query I came up with, thanks.
Tom