CakePHP - Virtual field issue using Paginator? - mysql

The following SQL query in phpMyAdmin returns exactly what I expect:
SELECT d.office_id, o.city, sum(d.`nb_followers`) as total_followers FROM `data` as d
LEFT JOIN offices as o on d.office_id = o.id
WHERE d.`year` = 2014 AND d.`month` = 10 AND d.`day` = 01
Group by d.`office_id`
ORDER BY total_followers DESC limit 10
In my Controller :
$this->Paginator->virtualFields = array(
'followers' => 'SUM(Data.nb_followers)',
'id' => 'Office.office_id'
);
$this->Paginator->settings = array(
'fields' => array('id', 'Office.city', 'Data.followers'),
'joins' => array(
array(
'table' => 'data',
'alias' => 'Data',
'type' => 'inner',
'conditions' => array(
'Office.id = Data.office_id',
'year = ' . date('Y', mktime(0, 0, 0, date('m'), 1, date('Y'))),
'month = ' . date('m', mktime(0, 0, 0, date('m'), 1, date('Y'))),
'day = 01'
)
)
),
'group' => array('Data.id'), //Mal positionné à la base mais vérifier si activé n'impacte pas les résultats
'order' => array('Data.followers' => 'desc')
//'limit' => 1
);
$dataTop = $this->paginate('Office');
But I get this Error :
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Data.followers' in 'field list'
SQL Query: SELECT Office.id, Office.city, Data.followers FROM ebd.offices AS Office inner JOIN ebd.data AS Data ON (Office.id = Data.office_id AND year = 2014 AND month = 10 AND day = 01) WHERE 1 = 1 GROUP BY Data.id LIMIT 20
Need Your Help Thank you

I did a test in my web app and putted a virtual field in one of my models. The virtual field was a field from a related table and it seems that it does not work. It outputs an sql error. So i remembered from the documentation the subquery command.
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#sub-queries
I dont know if this works but i will try to give you an example that might suite your needs
$db = $this->Office->getDataSource();
$subQuery = $db->buildStatement(
array(
'fields' => array('followers' => 'SUM(Data.nb_followers)'),
'table' => 'datas',
'alias' => 'Data'
),
$this->office);
$fields[] = $subQuery;
$fields[] = 'id';
$fields[] = 'Office.city';
I hope this guides you to the right direction.

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.

How to get count only today's post in get_terms wordpress

$termscat = get_terms([
'taxonomy' => 'newscategories',
'orderby' => 'count',
'order' => 'DESC',
'hide_empty' => false
]);
I am using above code to get post counts and is returning all post but i want to filter data only by todays date.
I think you want something like this.
SELECT count(post.ID) as count,rel.term_taxonomy_id,terms.name FROM {$wpdb->base_prefix}posts as post INNER JOIN {$wpdb->base_prefix}term_relationships as rel ON post.ID=rel.object_id INNER JOIN {$wpdb->base_prefix}terms as terms ON rel.term_taxonomy_id= terms.term_id WHERE post_date LIKE '$currentDate%' AND post.post_type='$post_type' GROUP BY rel.term_taxonomy_id ORDER BY count DESC
get_terms() used to get terms not posts.
if you want to get posts of current date then you can use the code below
$today = date( 'Y-m-d' );
$args = array(
'post_type' => 'vehicle',
'date_query' => array(
//set date ranges with strings!
'after' => 'today',
//allow exact matches to be returned
'inclusive' => true,
),
);
$query = new WP_Query( $args );
You can get more information on this https://codex.wordpress.org/Class_Reference/WP_Query#Date_Parameters
$today['year'] = current_time('Y');
$today['mon'] = current_time('m');
$today['mday'] = current_time('d');
$args = array(
'post_type' => 'news',
'date_query' => array(
array(
'year' => $today['year'],
'month' => $today['mon'],
'day' => $today['mday'],
),
),
'tax_query' => array(
array(
'taxonomy' => $tex_name,
'field' => 'term_id',
'terms' => $term_id,
),
),
);
$query = new WP_Query( $args );
$total = $query->found_posts;

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.