4

As part of a larger query with dynamically-generated elements, I need to do a left join and count. This is the query I need.

SELECT slug, name, count(client_tests.id) AS test_count
  FROM clients
  LEFT JOIN client_tests ON clients.id = client_tests.client_id
  GROUP BY clients.id;

I've tried to build a join query, but Lithium seems to be expecting the join to be part of a relationship (no relationships are defined), as shown below (ignoring the count for now).

$join = new Query(array(
  'source' => 'client_tests',
  'model' => '\app\models\ClientTest',
  'type' => 'LEFT',
  'constraint' => array('Client.id' => 'ClientTest.client_id'),
));
$clients = Client::all(array(
  'conditions' => $conditions,
  'group' => 'Client.id',
  'joins' => array($join)
));

This results in Notice: Undefined index: ClientTest in /usr/local/www/oars/libraries/lithium/data/collection/RecordSet.php on line 340, which seems to be relationship-related code.

If I do define a hasMany relationship between Client and ClientTest, which will handle building the left join for me, is there a way to get the Client fields and the count?

$clients = Client::all(array(
  'fields' => array('slug', 'name', 'count(ClientTest.test_id) as test_count'),
  'conditions' => $conditions,
  'group' => 'Client.id',
  'with' => 'ClientTest'
));

This results in ( ! ) Notice: Undefined index: count(ClientTest in /usr/local/www/oars/libraries/lithium/data/source/Database.php on line 650, so either it's not possible or I'm using the wrong syntax.

I could simply issue the query directly with Client::connection()->read($sql), but as there are dynamic elements to the query, I'd have to build the SQL anyway.

Is there a way to get the above methods to work, or should I go with manually building the SQL?

michaeltwofish
  • 4,096
  • 3
  • 28
  • 32

4 Answers4

1

If I'm understanding you correctly you already have the SQL query that returns the result set you're looking for but are having troubles with lithium. I would suggest trying this. If you create a view of the query that you need in SQL, you could then have lithium send its a simple request to the view instead. I have absolutely no experience with lithium but I hope that helps. Good luck.

Zane
  • 4,129
  • 1
  • 21
  • 35
0

I must first admit that I am not familiar with Lithium. However, there are two ways to approach this in SQL, which you might as well try.

I am assuming that you are trying to get the total number of rows returned as an additional column on each row.

The first requires something called window functions (aka analytic functions in Oracle). The query would look like:

SELECT *, count(*) over (partition by clients.id) AS test_count
FROM clients LEFT JOIN client_tests
     ON clients.id = client_tests.client_id

The second approach is used in databases that do not support this. To handle it with one query, the following works:

with q as (SELECT c.*, <whatever columns you want from client_tests
           FROM clients LEFT JOIN
                client_tests
                ON clients.id = client_tests.client_id
          )
select q.*, qsum.test_count
from q join
     (select id, count(*) as test_count
      from q
      group by id
     ) qsum
     on q.id = qsum.id

Perhaps one of these will work in your case.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
  • Writing the query isn't the problem, the best way to make it work in Lithium is specifically the question I've asked. – michaeltwofish May 06 '12 at 08:28
  • Your original query does not make sense as SQL. It has "select *" with a group by. If you start with correct SQL query, perhaps the rest will fall in place. – Gordon Linoff May 06 '12 at 12:27
  • I appreciate your help, and I was sloppy with the SQL, but the query isn't the issue. It's in the question to illustrate what I want to end up with but it's not used as input anywhere. – michaeltwofish May 07 '12 at 02:38
0

Your query seems weird. Try this:

SELECT slug, name, count(client_tests.id) AS test_count
FROM clients
LEFT JOIN client_tests ON clients.id = client_tests.client_id
GROUP BY clients.id;
Bohemian
  • 412,405
  • 93
  • 575
  • 722
0

Seems like you simply missTyped your table name,

'constraint' => array('Client.id' => 'ClientTest.client_id')

But you have :

LEFT JOIN client_tests ON clients.id = client_tests.client_id

Did you just made a mistake between client_tests and ClientTest?

Ludovic Migneault
  • 140
  • 1
  • 4
  • 19