cakephp mysql group by query - php

In the following cakephp mysql query, how do I find number of rows grouped each time?
$groupBy = 'PropertyViewer.ip_address';
$this->paginate = array(
"group" => array( $groupBy ),
"order" => array( "PropertyViewer.id desc" ) );
$view_info = $this->paginate( 'PropertyViewer', $conditions );
$this->set( 'view_info', $view_info );`

You can do it like in the following way, however I did not try it but it will work.
$groupBy = 'PropertyViewer.ip_address';
$this->paginate = array( "fields" => (..., 'COUNT(PropertyViewer.id) AS total_rows),
"group" => array( $groupBy ),
"order" => array( "PropertyViewer.id desc" ) );
$view_info = $this->paginate( 'PropertyViewer', $conditions );
$this->set( 'view_info', $view_info );`
Or you can also create a virtual Field in your model, if you need it to use frequently.

Related

CakePHP - Pagination total count differs from actual count when using DISTINCT

I have a find method that uses a DISTINCT clause to get results from my Model. The Controller code looks like below
$options = array(
'limit' => 10,
'fields' => array(
'DISTINCT id', 'title',
),
'contain' => array(
'Dealer' => array('id'),
),
'paramType' => 'querystring'
);
$this->Paginator->settings = $options;
$cars = $this->Paginator->paginate('Car'); // returns 6 distinct rows
The above query return 6 distinct rows and 12 total rows. So when I am displaying, the screen shows 6 distinct rows
However in the View, when I use
echo $this->Paginator->param('count'); // returns 12
I get a count of 12
I checked the SQL Log and noticed that the count query is not using the distinct clause. Any idea how I can override the Paginator count query to use the DISTINCT clause?
Found the solution,
In controller add distinct as an array parameter with other pagination options. So if I was trying to retrieve a list of Cars in my inventory with 10 cars at a time, the options would have a DISTINCT clause in the fields parameter and a separate parameter called distinct would also be added as shown below
$options = array(
'conditions' => $conditions,
'joins' => $joins,
'limit' => 10,
'fields' => array(
'DISTINCT Car.id', 'title', 'user_id'),
'contain' => array(
'Dealer' => array('id'),
),
'paramType' => 'querystring',
'distinct' => 'Car.id'
);
$this->Paginator->settings = $options;
$cars = $this->Paginator->paginate('Car');
In Model, use the below function to override the original paginateCount method
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
$parameters = compact('conditions', 'recursive');
if (isset($extra['distinct'])) {
$parameters['fields'] = 'DISTINCT ' . $extra['distinct'];
$count = $this->find('count', array_merge($parameters, $extra));
} else {
// regular pagination
$count = $this->find('count', array_merge($parameters, $extra));
}
return $count;
}
No change in View

CakePHP Retrieving data from multiple tables with select conditions

I am building an application using CakePHP and I am stuck on a problem retrieving data using a series of joins. In the simplified example below the join with the alias Delivery could have more than record and I want to bring back the record with a max value in a particular field in that table.
$inv_conditions = array( 'Invoice.invoice_date >=' => $DateFormatter->dateForDB($dateFrom),
'Invoice.invoice_date <=' => $DateFormatter->dateForDB($dateTo),
'Invoice.id >' => 385380 );
$join = array(array(
'table' => 'jobs',
'alias' => 'Jobs',
'type' => 'LEFT',
'conditions' => array('Invoice.job_id = Jobs.JOB_ID' )
),
array(
'table' => 'functional',
'alias' => 'Delivery',
'type' => 'LEFT'
'conditions'=> array('AND ' => array('Invoice.job_id = Delivery.JOB',
'Delivery.TYPE_STAGE = 1')
)
)
);
$invoices = $this->Invoice->find("all", array(
"fields" => array(
'Invoice.id',
'Invoice.job_id',
'Invoice.invoice_no',
'Invoice.consolidated_type',
'Invoice.customer_id_tbc',
'Invoice.invoice_date',
'Invoice.invoice_reference',
'Invoice.invoice_req',
'Jobs.PAYMENT_TYPE',
'Jobs.CUSTOMER',
'Jobs.MOST_RELEVANT_LINE',
'Delivery.DEPARTURE_DATE',
'Delivery.CNOR_CNEE_NAME',
'Delivery.TOWN_NAME',
),
"conditions" => $inv_conditions,
"joins" => $join
)
);
}
I can do this with SQL no problem as follows:
SELECT
jobs.JOB_ID,
jobs.CUSTOMER,
functional.JOB_LINE_ORDER,
functional.CNOR_CNEE_NAME,
functional.TOWN_NAME
FROM jobs JOIN functional ON
jobs.JOB_ID = 'M201409180267'
AND
functional.JOB = jobs.JOB_ID
AND
functional.TYPE_STAGE = 0
AND
functional.JOB_LINE_ORDER =
(SELECT MAX(JOB_LINE_ORDER) FROM functional
WHERE functional.JOB = 'M201409180267' AND functional.TYPE_STAGE = 0)
I have tried using the following to the conditions array:
'conditions' => array('AND ' =>
array( 'Invoice.job_id = Delivery.JOB',
'Delivery.TYPE_STAGE = 1'
'Delivery.JOB_LINE_ORDER = MAXIMUM(Delivery.JOB_LINE_ORDER)' )
)
This does bring back results but not the correct ones and the resulting SQL generated by Cake does have a select in the where clause. Is there a way of doing this when retrieving data in cake where the sql statement created will have a select in the where clause.
Any suggestions would be greatly appreciated.
Thanks
Bas
You need to use subquery to generate the select in the where clause. You can create a method in your model that does this and call it from your controller.
$subQuery = $db->buildStatement(
array(
'fields' => array(''),
'table' => $db->fullTableName($this),
'alias' => 'aliasName',
'limit' => null,
'offset' => null,
'joins' => array(),
'conditions' => $conditionsArray,
'order' => null,
'group' => null
),
$this
);
$subQuery = ' <<YOUR MAIN QUERY CONDITION (' . $subQuery . ') >>';
$subQueryExpression = $db->expression($subQuery);
$conditions[] = $subQueryExpression;
return $this->Model->find('list', compact('conditions'));

SQL query against an array?

Is there any kind of php library to execute SQL queries agains arrays?
Something like this:
$array = array(
array(
"field_a" => "first_a"
"field_b" => "something"
),
array(
"field_a" => "second_a"
"field_b" => "else"
),
array(
"field_a" => "third_a"
"field_b" => "something"
)
);
$rows = arrayQuery($array, "SELECT field_a WHERE field_b = 'something'");
/*
$rows = array(
array(
"field_a" => "first_a"
),
array(
"field_a" => "third_a"
)
);
*/
Found something similar: http://blog.phpdeveloper.org/?p=61, but that is not a query.
I believe that LINQ for PHP would do the trick. I think this is a close as it gets to 'querying arrays' in PHP.

CakePHP this->paginate not using order field

No matter what I do I can't get it to respect the order I specify.
$this->paginate = array(
'Car' => array(
'limit' => 6,
'order' => array(
'Car.year' => 'desc'
),
'table' => 'cars'
)
);
Generated SQL:
SELECT `Car`.`id`, ... `Car`.`year`,... FROM `cars` AS `Car` WHERE 1 = 1 LIMIT 6
Turns out I was using a :sort in my url parameters. Once I took that out all was well :)
If you only have one item, you don't need/shouldn't use an array:
//one thing
var $order = "Model.field DESC";
//multiple things
var $order = array("Model.field" => "asc", "Model.field2" => "DESC");
(per this page)
Note too that virtual fields are ignored by default when paginating.
See "Control which fields used for ordering" in Cake 2.0 Pagination documentation.
Example:
$this->MyModel->virtualFields['count'] = 0;
$this->Paginator->settings = array(
'fields' => 'COUNT(id) AS MyModel__count',
'group' => ('MyModel.group_id'),
'order' => array('MyModel__count' => 'DESC'),
);
// IMPORTANT: pass sortable fields including the virtual field as 3rd parameter:
$log = $this->Paginator->paginate('MyModel', null, array('MyModel__count', 'id'));

How to get all table columns without defining them in query?

I have two tables, User and Company. I have joining them like this:
$table = $this->getDbTable();
$select = $table->select();
$select->setIntegrityCheck( false );
$select->from( array('User'), array( 'id' => 'id',
'name' => 'User.name',
'gender' => 'User.gender',
'Company_id' => 'User.Company_id'
));
$select->join( 'Company', 'Company.id = User.Company_id',
array( 'Company_name' => 'Company.name' ,
'Company_address' => 'Company.address'
));
$rows = $table->fetchAll( $select );
It is working and giving me accurate result. Problem is that I have to mentions column names in above codes. I want to get all columns without mentioning them in above piece of code.
For example I want something like this that get all columns(But it is not providing all column values):
$table = $this->getDbTable();
$select = $table->select();
$select->setIntegrityCheck( false );
$select->from( array('User') );
$select->join( 'Company', 'Company.id = User.Company_id' );
$rows = $table->fetchAll( $select );
Thanks
Leaving away the second parameter to the from call should work: http://framework.zend.com/manual/en/zend.db.select.html#zend.db.select.building.columns

Categories