views:

110

answers:

2

Hello everyone,

I have 3 tables, which are each 1:n.

an entry in table1 has n entries in table2, and so on.

lets call them cars, wheels, and screws for illustration. Screws can be clean(1) or rusty(2)

I am joining them together, because I want to count 2 things.

First, I want to have rows telling me how many good/bad screws per wheel I have for each car. So basically I am getting:

car_id    wheel_id   screw_state  count(screws)
   1          1           1          3
   1          1           2          7
   1          2           1          5
   1          2           2          3
   2          1           1          1
                ... and so on...

Now I want a second fact, namely how many rusty and clean screws I have for all wheels per car, without needing to know each specific number per wheel. So basically now I just leave off the GROUP BY over wheel_id, like this:

car_id    screw_state  count(screws)
   1          1             8
   1          2            10
   2          1             1
                ... and so on...

The thing is, I would need both of them in one single query, because else I'd have a lot of sorting and rearranging to do. I believe the second, easier count over the total screws per car should be done as a subquery, but can I join the first, bigger query easily with a subquery?

How is this done? I would be happy over a quite specific answers, because I am not really an SQL wizard.

edit : I am working on an ORM, so funky thinks like below (hacking the col values to some constant) cant be done there easily. I have to get this solution working there, so JOIN/subquery/UNIONs without funky workarounds would be great.

Greetings, Tom

+1  A: 
SELECT car_id, wheel_id, screw_state, count(screws)
  FROM cars C, wheels W, screws S
 WHERE W.car_id = C.car_id
   AND S.wheel_id = W.wheel_id
 GROUP BY car_id, wheel_id, screw_state
UNION ALL
SELECT car_id, -1 AS wheel_id, screw_state, count(screws)
  FROM cars C, wheels W, screws S
 WHERE W.car_id = C.car_id
   AND S.wheel_id = W.wheel_id
 GROUP BY car_id, screw_state
ORDER BY car_id

you can UNION 2 queries, the second one for all wheels per car, that's why wheel_id = -1.

result:

    car_id    wheel_id   screw_state  count(screws)
       1          1           1          3
       1          1           2          7
       1          2           1          5
       1          2           2          3
       1         -1           1          8
       1         -1           2         10
       2          1           1          1
       2         -1           1          1
...
najmeddine
Tested it now, and sadly my MySQL server doesnt like that "-1 wheel_id" syntax. I tried writing wheel_id = -1, it seems to work, apart from the fact that in the output, wheel_id comes out as 0 for the total counts, instead of -1, but the rest seems to work.
Tom
I used MS SQL server syntax, may be for MySQL you have to put : -1 as wheel_id. I fixed it in my answer.
najmeddine
SELECT car_id, -1 , screw_state, count(screws) works for me
Tom
It's weird, as in MySQL manual it gives example as : SELECT 1+1, SELECT 1 AS foo... May be it's the 'minus' sign, you have to put it like: select car_id, (-1) As wheel_id,... what error message do you get?
najmeddine
I simply get a "#1064 - You have an error in your SQL syntax;", tried until now: -1 wheel_id, -1 AS wheel_id, (-1) as wheel_id, -1:wheel_id.all those failed, the only ones that worked were wheel_id = -1 (but have wrong results) or simply -1 without wheel_id at all
Tom
Last try, add backticks to wheel_id like this: -1 As ``wheel_id``. If it still doesn't work, to tell you the truth I'm not an expert at MySQL syntax I can't help you more. Besides it works like that.
najmeddine
+1  A: 

A quick search says that MySQL supports GROUPING SETS. This is a good candidate for that feature:

SELECT car_id, wheel_id, screw_state, count(screws)
FROM cars C
JOIN wheels W ON W.car_id = C.car_id
JOIN screws S ON S.wheel_id = W.wheel_id
GROUP BY GROUPING SETS (
  (car_id, screw_state, wheel_id),
  (car_id, screw_state)
)
ORDER BY car_id, wheel_id, screw_state
Steve Kass
Good idea, but MySQL doesn't support grouping sets. Even PostgreSQL just got the feature recently.
Seun Osewa
Steve Kass
no prob, if this had worked, your answer would have been my first choice, its more compact and elegant.
Tom