views:

276

answers:

7

don't know if this is possible.. I'm using sqlite3 schema:

CREATE TABLE docs (id integer primary key, name string);
CREATE TABLE revs (id integer primary key, doc_id integer, number integer);

I want to select every job joined with only one of its revisions, the one with the highest number. How can I achieve this? Right now I'm doing a left join and getting everything and then I'm filtering it in the application, but this sucks..

(by the way, can you suggest me a good and easy introductory book on databases and how they work and maybe something about sql too..) thanks!

A: 

Here is a very good list of books for Database Design

http://stackoverflow.com/search?q=database+book

Raj More
+3  A: 

try this

   Select * From docs d
      Join revs r
         On r.doc_id = d.id
   Where r.number = 
         (Select Max(number ) from revs
          Where Doc_Id = d.Id)

or, if you want the docs with no Revs (Is this possible?)

   Select * From docs d
      Left Join revs r
         On r.doc_id = d.id
           And r.number = 
                (Select Max(number ) from revs
                 Where Doc_Id = d.Id)
Charles Bretana
almost.. but you're selecting the rev with highest id, I want the one with highest "number". If I add id,max(number) then I get: "SQL error: only a single result allowed for a SELECT that is part of an expression"
luca
change it to r.numbers = (select max(number)... The only reason I didn't use the = and used IN is that some SQL dialects are quirky about a subquery which returns a scalar instead of a set, whereas the IN syntax is almost universally supported.
Cade Roux
@luca: sorry, my bad, I missed that, edited to change it to do the max(number)
Charles Bretana
+2  A: 

Not sure if your engine supports this, but typically, you would do something like this in ANSI SQL:

SELECT docs.*
    ,revs.*
FROM docs
INNER /* LEFT works here also if you don't have revs */ JOIN revs
    ON docs.id = revs.doc_id
    AND revs.number IN (
        SELECT MAX(number)
        FROM revs
        WHERE doc_id = docs.id
    )

There are a number of ways to write equivalent queries, using common table expressions, correlated aggregate subqueries, etc.

Cade Roux
Good! Am I correct in thinking that this query is pretty work intensive? It's actually doing a select for every doc.. I will have lots of docs, but only a few revs for each one.. it doesn't make any sense to index the number field does it?
luca
On the face of it, this would appear to do a subselect on each row, but in my experience, the SQL Server optimizer makes this as equivalent to those with CTEs or correlated subqueries. I just put this down as the most readable for you. Like I said, there's lots of ways to skin this cat (I think it shows up 5 times daily here, and I give different answers depending on my feeling). Your mileage may vary with your engine.
Cade Roux
OrbMan's solution - apparently pre-aggregating and joining - is typically what most engines actually do (I actually usually use that form). You would have to look at the execution plan to see how your engine handles it.
Cade Roux
+2  A: 
select d.*, r.max_number
from docs d
left outer join (
    select doc_id, max(number) as max_number
    from revs
    group by doc_id
) r on d.id = r.doc_id
RedFilter
+1  A: 

Database Design : Database Design for Mere Mortals by Hernandez

SQL : The Practical SQL Handbook

If you want to hurt your head, any of the SQL books by Joe Celko.

DaveE
A: 

If every job has revisions (e.g., starting with rev 0), I would use the same approach as OrbMan, but with an inner join. (If you are certain you are looking for a 1-to-1 match. why not let SQL know, too?)

select d.*, r.max_number
from docs d
inner join
(
    select doc_id, max(number) as max_number
    from revs
    group by doc_id
) r on d.id = r.doc_id
ethyreal
A: 

I'd recommend "A Sane Approach to Database Design" as an excellent introduction to good design practices. (I am slightly biased. I wrote it. But hey, so far it has a 5-star average review on Amazon, none of which reviews were contributed by me or any friends or relatives.)

Jay