CakePHP Database Query Count(Case When) - mysql

I'm using CakePHP and cannot seem to translate this SQL query I did on the workbench. It's exactly what I want to do but I cannot seem to make it work.
This is my query on MySQL:
select
docs.id, docs.schoolId, schools.name, docs.datesubmitted, docs.status,
uploads.iddocs,
COUNT(*),
COUNT(case uploads.staff_checked when 1 then 1 else null end)
FROM
docs as docs, schools as schools,
uploads as uploads
where
docs.schoolId = schools.schoolId AND
docs.id = uploads.iddocs AND
docs.status ="Submitted"
group by
docs.id;
What I need to do is combine three tables: Docs, Schools, and Uploads.
The two counts: COUNT(case when) and COUNT(*) indicate the number of documents reviewed (COUNT(case when)) and total documents needed to be reviewed (COUNT(*)).
So far MySQL is showing what I need. Can someone figure out how to do it in Cake?

Try the following query
$this->virtualFields = array(
'count_case_uploads_staff_checked_when_1_then_1_else_null_end' => 'COUNT(case uploads.staff_checked when 1 then 1 else null end)',
'count' => 'COUNT(*)',
);
$options = array(
'fields' => array(
'Doc.id',
'Doc.schoolId',
'schools.name',
'Doc.datesubmitted',
'Doc.status',
'uploads.iddocs',
'Doc.count_case_uploads_staff_checked_when_1_then_1_else_null_end',
'Doc.count',
),
'joins' => array(
array(
),
),
'conditions' => array(
'Doc.schoolId = schools.schoolId',
'Doc.id = uploads.iddocs',
'Doc.status' => 'Submitted',
),
'group' => array(
'Doc.id',
),
);
$data = $this->find('all', $options);

Related

Wordpresss - WP_query count

I need to count how many times my date recorded in the meta key:metakey_AMC_data, in format (d-m-Y) it is contained in the database by comparing it with the current date
$mostra_data_corrente = date('d-m-Y');
$query = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}postmeta
WHERE (meta_key = 'metakey_AMC_data'
AND meta_value = '$mostra_data_corrente')");
$conta_risultati = count($query);
and this I can do perfectly.but now my need is to execute the first query by linking another AND, and specify when the term slug is equal to the category of the event (terms taxonomy), obviously the query is incorrect
SELECT * FROM {$wpdb->prefix}postmeta
WHERE (meta_key = 'metakey_AMC_data'
AND meta_value = '$mostra_data_corrente')
AND(slug = 'aperitivi') "
how can i do this?
You can get that count as well. You need to modify query (code) like follow:
$qry = array(
'post_type' => 'post', // mention your post type to narrow down searching through postmeta table
'meta_query' => array(
array(
'meta_key' => 'metakey_AMC_data',
'meta_value' => $mostra_data_corrente,
'compare' => '='
)
),
'tax_query' => array(
array(
'taxonomy' => 'nameoftaxonomy', // Write the name of taxonomy that you have assinged while you created a CPT (custom post type)
'field' => 'slug',
'terms' => 'aperitivi',
)
)
)
$the_query = WP_Query($qry);
echo $the_query->post_count;
You have to make some necessary changes in above code to suite your requirements. I've added comment where you have to do changes.

Convert the MySql query to CakePhp 2.0

How do I convert this MySql query to CakePhp's find.
And please tell me how can i practice writing Find queries in cakephp
select distinct trips.fk_userid from spots, trips
where spots.fk_tripid = trips.id
and trips.isapproved = 1
and spots.id in (".$row[$first_index]['spot_list'].")
The model can be Trip and you can query like this
$this->Trip->query("select distinct trips.fk_userid from spots, trips where spots.fk_tripid = trips.id and trips.isapproved = 1 and spots.id in (".$row[$first_index]['spot_list'].")");
or
You should create Trip and Spot model and in Trip model, you have to have this in Spot model:
public $belongsTo = array(
'Trip' => array(
'className' => 'Trip',
'foreignKey' => 'fk_tripid'
)
);
and query it like this:
$this->Spot->find('all', array(
'fields' => array("distinct Trip.fk_userid"),
'conditions' => array(
'Trip.isapproved' => 1,
'Spot.id' => $row[$first_index]['spot_list']
)
));

cakephp set condition on MAX()

I need max submitted orders in the last 30 days. max field is a virtualField.
public $virtualFields = array(
'max_submitted' => "MAX(`WorkRecord`.`submitted`)"
);
I get error #1054 - Unknown column 'WorkRecord.max_submitted' in 'field list'
SELECT `WorkRecord`.`id`, `Order`.`fee`, `Order`.`order_id`,
`Order`.`min_sources`, `Order`.`min_references`, `Order`.`am_level`,
`Order`.`am_standard`, `Order`.`am_type`, `Order`.`am_subject`, `Order`.`am_word_count`,
`Order`.`ref_style`, `Order`.`service`, `BriefInstalment`.`deadline`,
`BriefInstalment`.`id`, (MAX(`WorkRecord`.`submitted`)) AS `WorkRecord__max_submitted`
FROM `writers`.`work_records` AS `WorkRecord`
RIGHT JOIN `torg`.`temp_orders` AS `Order` ON (`Order`.`order_id` = `WorkRecord`.`order_id` AND `Order`.`status2` > 2 AND `Order`.`am_type` NOT LIKE '%phd%') LEFT JOIN `writers`.`brief_instalments` AS `BriefInstalment` ON (`WorkRecord`.`brief_instalment_id` = `BriefInstalment`.`id`)
WHERE `WorkRecord`.`writer_id` = 7827
AND `WorkRecord`.`withdrawn` IS NULL
AND `WorkRecord`.`max_submitted` BETWEEN NOW() - INTERVAL 30 DAY AND NOW() GROUP BY `Order`.`order_id`
You can't use aggregate function results in where clauses, because the results of the aggregate (e.g. max()) will NOT be available when the where clause is being applied.
Move the max() to a `having:
SELECT ..., max(foo) AS foo
FROM ...
WHERE ...
HAVING foo BETWEEN ...
having is basically applied as the last step just before the results are sent over the client. By that time, all of the calculations/aggregations are done.
For others. Here is what I should have done.
$workRecords = $this->find('all', array(
'fields' => array(
'WorkRecord.id', 'MAX(`WorkRecord`.`submitted`) AS submitted',
'Order.fee', 'Order.order_id', 'Order.min_sources', 'Order.min_references', 'Order.am_level', 'Order.am_standard',
'Order.am_type', 'Order.am_subject', 'Order.am_word_count', 'Order.ref_style', 'Order.service'
),
'conditions' => array(
'WorkRecord.writer_id' => $userId,
'WorkRecord.withdrawn IS NULL'
),
'joins' => array(
array(
'table' => 'torg.temp_orders',
'alias' => 'Order',
'type' => 'RIGHT',
'conditions' => array(
'Order.order_id = WorkRecord.order_id',
'Order.status2 >' => 2,
"Order.am_type NOT LIKE '%phd%'"
)
)
),
'contain' => array(
'BriefInstalment.deadline'
),
'group' => array(
'Order.order_id HAVING `submitted` BETWEEN NOW() - INTERVAL 30 DAY AND NOW()'
)
));

MYSQL to CakePHP

I want to convert following complex mysql into cake's find expression:
SELECT p1, p2
FROM
(
SELECT IFNULL(a.c2, '10') AS p1, IFNULL((SELECT MAX(c.c1) FROM my_table c WHERE c.c1>p1), '30') AS p2
FROM my_table a
WHERE
(
(a.user_id = 2) AND (a.c1 BETWEEN '10' AND '30')
)
) as temp
WHERE p2 > 100
ORDER BY p1;
I tried following
http://dogmatic69.com/sql-to-cakephp-find-converter
but unable to generate the desired expression.
Please help. I really don't know how to handle such complex expressions (I do not prefer to use query in cakephp)
Thanks
Let me just convert your query into the cakephp way
if table a's model is A:
$fields = "IFNULL(A.c2, '10') AS p1, IFNULL((SELECT MAX(C.c1) FROM my_table c WHERE C.c1>p1), '30') AS p2";
$conditions = "A.user_id=2 AND A.c1 BETWEEN '10' AND '30'";
$inner_querry = $this->A->find("all", compact("fields", "conditions"));
$fields = "p1,p2";
$conditions = "p1 IN ($inner_querry) AND p2 IN($inner_query) AND p2 > 100";
$order = "p1";
$query = $this->A->find("all", compact("fields", "conditions", "order"));
debug($query); //check results of for error.
I think that sometimes it's not so wrong to use Model->query(), but let' try to use cake functions.
In fact the only way I see to obtain that particular query is building the subqueries with buildStatement() function (and at the end you still have to call Model->query() so...). But just for fun.
Assuming your model name is MyTable, in your MyTablesController do:
$p1 = "IFNULL(a.c2, '10') AS p1";
$db = $this->MyTable->getDataSource();
$subQuery = $db->buildStatement(
array(
'table' => $db->fullTableName($this->MyTable),
'alias' => 'C',
'fields' => array('MAX(c.c1)'),
'conditions' => array(
"C.c1 > " => 'p1',
)
),
$this->MyTable
);
$p2 = "IFNULL(".$subQuery.") AS p2";
$subQuery = $db->buildStatement(
array(
'table' => $db->fullTableName($this->MyTable),
'alias' => 'A',
'fields' => array($p1, $p2),
'conditions' => array(
"A.user_id" => 2,
"A.c1 BETWEEN ? AND ?" => array(10,30)
)
),
$this->MyTable
);
$query = $db->buildStatement(
array(
'table' => $subQuery,
'alias' => 'test',
'fields' => array('p1', 'p2'),
'conditions' => array(
"p2 > " => 100,
)
),
$this->MyTable
);

ISNULL not working in order in CAKEPHP

I am using LEFT join and as a result getting null values for is_read column in Messages table. I want to keep the nulls at bottom when ordering. I'm using this in paginator. Following is the my code for doing the same:
$this->Paginator->settings = array(
'fields' => array('User.*'),
'joins' => array(
array('table' => 'messages',
'alias' => 'Message',
'type' => 'LEFT',
'conditions' => array(
'User.id = Message.user_from_id'
)
),
),
'limit' => 20,
'group' => array('User.id'),
'order' => array('ISNULL(Message.is_read)' => 'asc','Message.is_read' => 'asc', 'Message.created' => 'asc'),
);
The query Cakephp generates for this is as follows:
SELECT `User`.*, (CONCAT(`User`.`first_name`, ' ', `User`.`last_name`)) AS `User__full_name` FROM `srs_development`.`users` AS `User` LEFT JOIN `srs_development`.`messages` AS `Message` ON (`User`.`id` = `Message`.`user_from_id`) WHERE 1 = 1 GROUP BY `User`.`id` ORDER BY `Message`.`is_read` asc, `Message`.`created` asc LIMIT 20
ISNULL function is getting omitted in the final query.
Also please suggest a way to accomplish this without using custom pagination() if possible.
Aggregate functions didn't work in the order clause when using Pagination component. I tried declaring a virtual field in Message model as:
public $virtualFields = array(
'sortme' => "ISNULL(Message.is_read)",
);
So finally, declaring it as virtual field in the Message model did the job.
Thank you everyone.