how to convert propel criteria in symfony - php

select a.id, b.title, b.start_time, b.end_time from tv_channel a
left join tv_program b on a.id = b.tv_channel_id and b.start_time >= ‘2011-09-23 12:00:00′ and b.end_time <= '2011-09-23 14:30:00'
order by a.code
limit 0, 10;
–pager object
tnx

What's the question ? Do you want to write this SQL query in Propel ?
<?php
TvChannelQuery::create('a')
->joinTvProgram('b')
->addJoinCondition('b', 'b.StartTime >= 2011-09-23 12:00:00')
->addJoinCondition('b', 'b.EndTime >= 2011-09-23 14:30:00')
->orderByCode()
->limit(10)
;
Something like that should work but be be careful about values passed in addJoinCondition, there is no binding here and if you want to change these values you have to use it to prevent SQL injections or other security issues.

$c = new Criteria();
$c->addLeftJoin(tv_channel.id = tv_program .channel_id);
$c->add(tv_program.start_time, '2011-09-23 12:00:00', Criteria::GREATER_EQUAL);
$c->add(tv_program.end_time, '2011-09-23 14:30:00', Criteria::LESS_EQUAL);
$c->addAscendingOrderByColumn(tv_channel.code);
$c->setLimit(10);
$rs = DoSelect($c); //actual select execution here...

Related

MySQLi join using date(now()) in where clause

I am running this query in phpmyadmin and it works fine. But on running it in joshcam's MySQLi Database class it gets wrong data
Query:
SELECT
s.az
, s.ta
, s.zamanSarfShode
, p.name
FROM
saateruzane s
JOIN
projhe p
JOIN
kareruzane k
WHERE
s.ProjheId = p.id
AND
k.id = s.ruzId
AND
k.ruzGregorian = date(now())
PHP code :
$con->join('projhe p', 's.ProjheId = p.id');
$con->join('kareruzane k', 'k.id = s.ruzId');
$con->joinWhere('kareruzane k','k.ruzGregorian', 'date(now())');
$tines = $con->get('saateruzane s',null,'s.az ,s.ta ,s.zamanSarfShode ,p.name');
The definition for joinWhere is
public function joinWhere($whereJoin, $whereProp, $whereValue = 'DBNULL', $operator = '=', $cond = 'AND')
So you don't need to pass in every part. Instead, try this:
$con->joinWhere('kareruzane k','k.ruzGregorian = date(now())');
Though better than date(now()) is CURDATE()
$con->joinWhere('kareruzane k','k.ruzGregorian = curdate()');
However, I'm not sure you should be using a join here, since it's part of the WHERE clause on your original query, not the JOIN clause. So instead do
$con->where('k.ruzGregorian = curdate()');
With just a fast look on this lib docs, I found this:
'createdAt' => $db->now(),
// createdAt = NOW()
https://github.com/joshcam/PHP-MySQLi-Database-Class#insert-query
In your case try use
$con->joinWhere('kareruzane k','k.ruzGregorian', $con->now());

Codeigniter: display two data in query with distinct and count

I'm try to display two data of one query using codeigniter.
$query = "SELECT count(distinct p.id_paciente), count(c.pacientes_id_paciente) FROM paciente p, cita c WHERE p.id_paciente=c.pacientes_id_paciente AND p.usuarios_id_usuario=43 AND p.aseguradoras_id_aseguradora=8 AND c.dia_cita>='2015-04-16' AND c.dia_cita<='2015-04-16'";
$sql = $this->db->query($query);
How can I to show the two results of count(distinct p.id_paciente) and the count(c.pacientes_id_paciente)
I try using
foreach ($sql->result_array() as $row)
{
echo $row['id_paciente'];
echo $row['pacientes_id_paciente'];
}
But only display the content of the array...
Thanks
There are several issues with your code:
Use aliases to name columns in the resultset to be able to address them later by name
SELECT COUNT(distinct p.id_paciente) AS count1, ...
^^^^^^
Don't interpolate query strings yourself. Use Codeigniter's query bindings
This may not be relevant to you but if dia_cita has time component to it (i.e. is of type datetime) you may want to change your WHERE condition to
c.dia_cita >= ? AND c.dia_cita < ? + INTERVAL 1 DAY
There is no need for foreach loop. You always get only one row with this query. Therefore use Codeigniter's row() or row_array().
That being said your code may look like
$sql = "
SELECT COUNT(DISTINCT p.id_paciente) AS count1,
COUNT(c.pacientes_id_paciente) AS count2
FROM paciente p JOIN cita c
ON p.id_paciente = c.pacientes_id_paciente
WHERE p.usuarios_id_usuario = ?
AND p.aseguradoras_id_aseguradora = ?
AND c.dia_cita >= ?
AND c.dia_cita < ? + INTERVAL 1 DAY
";
$bindings = array(43, 8, '2015-04-16', '2015-04-16')
$row = $this->db
->query($sql, $bindings)
->row_array();
echo $row['count1'], $row['count2'];

How to correctly prepare parameters with DoctrineDBAL on the following query?

I need to get the percentage of each possible values in the field column, over the total value of my table.
I found two way to get my result in SQL:
SELECT m.field, sum(m.value) * 100 / t.total
FROM my_table AS m
CROSS JOIN (
SELECT SUM(value) AS total FROM
WHERE year = 2000) t
WHERE m.year = 2000
GROUP BY m.field, t.total
And
SELECT m.field, sum(m.value) * 100 / (SELECT SUM(value) AS total FROM WHERE year = 2000)
FROM my_table AS m
WHERE m.year = 2000
GROUP BY m.field
But both are nested queries, and I don't know how to prepare statments with the Doctrine's QueryBuilder into a nested queries.
Is there a way to do it?
I have been trying to do so using querybuilder and DQL with no success. As it seems, DQL doesn't allow operations with subqueries in SELECT. What I've achieved so far:
$subQuery = $em->createQueryBuilder('m')
->select("SUM(m.value)")
->where("m.year = 2000")
->getDQL();
The following query works though doesn't calculate the percentage:
$query = $em->createQueryBuilder('f')
->select("f.field")
->addSelect(sprintf('(%s) AS total', $subQuery))
->addSelect('(SUM(f.value)*100) AS percentage')
->where("f.year = 2000")
->groupBy("f.field")
->getQuery()
->getResult();
However, if you try to add the division in the select in order to get the percentage and you use the subquery, it simply doesn't work. Looks like the construction it's not allowed in DQL. I've tried with an alias and with the subquery directly and neither of them worked.
Doesn't work:
$query = $em->createQueryBuilder('f')
->select("f.field")
->addSelect(sprintf('(%s) AS total', $subQuery))
->addSelect('(SUM(f.value)*100)/total AS percentage')
->where("f.year = 2000")
->groupBy("f.field")
->getQuery()
->getResult();
Doesn't work either:
$query = $em->createQueryBuilder('f')
->select("f.field")
->addSelect(sprintf('(SUM(f.value)*100)/(%s) AS percentage', $subQuery))
->where("f.year = 2000")
->groupBy("f.field")
->getQuery()
->getResult();
I'd suggest using SQL directly (Doctrine allows it). Using native sql queries and mapping the results would do the trick. There is no disadvantage in doing so.
Documentation
If you find a way of doing it using queryBuilder or DQL, please let me know.
Hope it helps.
yeah! the solution is:
$qs = $this
->createQueryBuilder('h');
$d = $qs ->select($qs->expr()->count('h'));
$e = $d->getQuery()->getScalarResult();
$qs->addSelect('(COUNT(h.id)*100 / :t) AS percentage')->setParameter('t', $e);
$qs->addGroupBy(sprintf('h.%s', $type));
return $qs->getQuery()->getResult();

MySQL Query Performance and Codeigniter

I have this MySQL query which I am loading in to my home controller and after running Codeigniter's $this->output->enable_profiler(TRUE); I get an execution time of 5.3044
The Query inside my model:
class Post extends CI_Model {
function stream($uid, $updated, $limit) {
$now = microtime(true);
$sql = "
SELECT
*
FROM
vPAS_Posts_Users_Temp
WHERE
post_user_id = ?
AND post_type !=4
AND post_updated > ?
AND post_updated < ?
UNION
SELECT
u.*
FROM
vPAS_Posts_Users_Temp u
JOIN
PAS_Follow f
ON f.folw_followed_user_id = u.post_dynamic_pid
WHERE u.post_updated > ?
AND post_updated < ?
AND (( f.folw_follower_user_id = ? AND f.folw_deleted = 0 )
OR ( u.post_passed_on_by = f.folw_follower_user_id OR u.post_passed_on_by = ? AND u.post_user_id != ? AND u.post_type =4 ))
ORDER BY
post_posted_date DESC
LIMIT ?
";
$query = $this->db->query($sql, array($uid, $updated, $now, $updated, $now, $uid, $uid, $uid, $limit));
return $query->result();
}
}
Is there anything I can do here to improve the execution time and therefore increase my page load?
Edit
Explain Results
MySQL Workbench Visual Explain
Maybe you won't believe it, but DON'T retrieve SELECT * in your SQL. Just write the fields you want to retrieve and I think it'll speed up a lot.
I've seen increases in speed of more than 20 times when executing a query (from 0.4secs to 0.02 secs) just changing * for required fields.
Other thing: If you have an auto_increment id on INSERT in your tables, DON'T use post_posted_date as ORDER field. Ordering by DATETIME fields is slow, and if you may use an INT id (which hopefully you will have as an index) you will achieve the same result quicker.
UPDATE
As required in the question, technical reasons:
For not using SELECT *: Which is faster/best? SELECT * or SELECT column1, colum2, column3, etc. This is for SQL, but for MySQL (not as complete as question before) mySQL Query - Selecting Fields
For Ordering by Datetime: SQL, SQL Server 2008: Ordering by datetime is too slow, and again, related to MySQL: MySQL performance optimization: order by datetime field
Bonus: Learning how to set the indexes: http://ronaldbradford.com/blog/tag/covering-index/
I would add indexes on post_user_id, post_updated and folw_follower_user_id.
In this case it may also be better to not use union and separate the query into two separate ones and then use PHP to combine to two result sets.
If you switched to using active record you could also look into caching, to get better performance
The rows column shows an estimate for how many rows needs to be examined, which as I understand, means that in your case, it has to scan 72 * 1 * 2627 * 1 * 2 rows, which is quite a lot.
Now, the trick is to bring down this number, and one way is to add indexes. In your case, I would suggest adding an index which contains:
post_user_id, post_type, post_updated, post_updated.
This should bring down the first result set, of 72 rows.
Now for the UNION, try using UNION ALL instead, as it is claimed to be faster.
If that doesn't fix the problem, I would suggest rewriting the query to not use a UNION call at all.
Try the query with left join as you are trying to union on same table
"SELECT
u.*
FROM
vPAS_Posts_Users_Temp u
LEFT JOIN PAS_Follow f ON f.folw_followed_user_id = u.post_dynamic_pid
WHERE (
u.post_user_id = ?
AND u.post_type !=4
AND u.post_updated > ?
AND u.post_updated < ?
)
OR
(
u.post_updated > ?
AND post_updated < ?
AND (( f.folw_follower_user_id = ? AND f.folw_deleted = 0 )
OR ( u.post_passed_on_by = f.folw_follower_user_id OR u.post_passed_on_by = ? AND u.post_user_id != ? AND u.post_type =4 ))
)
ORDER BY
u.post_posted_date DESC
LIMIT ?"
I think you can remove the UNION from the query and make use of left join instead and avoid the unnecessary conditions:
SELECT U.*
FROM vPAS_Posts_Users_Temp AS U
LEFT JOIN PAS_Follow AS F ON F.folw_followed_user_id = U.post_dynamic_pid
WHERE U.post_updated > ?
AND U.post_updated < ?
AND (
(
F.folw_follower_user_id = ? AND F.folw_deleted = 0
)
OR
(
U.post_passed_on_by = F.folw_follower_user_id OR U.post_passed_on_by = ?
)
)
ORDER BY
U.post_posted_date DESC
LIMIT ?
Also identify and set proper indexes in your tables.

How to convert normal sql query to Zend_Db_Select?

Hi I want to convert my normal mysql query to zend.db.select;
I want to use this script:
$select = $db->select();
// Add a FROM clause
$select->from( ...specify table and columns... )
// Add a WHERE clause
$select->where( ...specify search criteria... )
// Add an ORDER BY clause
$select->order( ...specify sorting criteria... );
$select->limit(20, 10);
for my query below
SELECT
IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid) friend1,c.UserName,
derived_messages.message, derived_messages.fromid, derived_messages.toid,
derived_messages.is_read,derived_messages.type,derived_messages.id as mesid,
derived_messages.date,
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1) as MesMapid
FROM
(
SELECT *
FROM messages
WHERE messages.deleted_by NOT
IN ( $user )
ORDER BY Date DESC
) derived_messages
INNER JOIN Users c ON c.MemberID = IF(derived_messages.toid = '$user', derived_messages.fromid,
derived_messages.toid)
WHERE (derived_messages.id IN
(SELECT M.message_id FROM messagesmapped M where M.message_id= derived_messages.id AND M.user_id ='$user' AND M.important = 1)
AND
(derived_messages.toid='$user' OR derived_messages.fromid='$user'))
GROUP BY friend1 ASC
ORDER BY derived_messages.date DESC, derived_messages.id DESC LIMIT $limit $offset
I hope someone can help m on this.
Thank you.
It's possible but unlikely someone will write the query for you.
My recommendation on tackling such a query is to write each individual subquery as its own Zend_Db_Select object and then build the final query using the subqueries that you already have objects for.
Zend_Db_Select doesn't directly support the IF function, so for that you will need to use Zend_Db_Expr to add that statement into your select.
Here is a basic example of what I am talking about. Let's build the following query:
SELECT IF(msg.toId = 'drew010', msg.fromId, msg.toId), id, name, age, history.ip
FROM users
JOIN history ON users.id = history.userId
WHERE users.id = (
SELECT id FROM users WHERE loginCount > 1000
)
GROUP BY id,
ORDER BY age DESC
First build the subselect that select users where loginCount > 1000.
$subquery1 = $db->select()
->from('users', array('id'))
->where('loginCount > ?', 1000);
Next, build the outer query with the IF function:
$cols = array(
new Zend_Db_Expr('IF(' . $db->quoteInto('msg.toId = ?', 'drew010') . '), msg.fromId, msg.toId'),
'id', 'name', 'age'
);
$query = $db->select()
->from('users', $cols)
->join('history', 'users.id = history.userId', array('ip'))
->where('id = ?', $subquery1)
->group('id')
->order('age DESC');
echo $query;
The output:
SELECT
IF(msg.toId = 'drew010', msg.fromId, msg.toId),
`users`.`id`,
`users`.`name`,
`users`.`age`,
`history`.`ip`
FROM `users`
INNER JOIN `history`
ON users.id = history.userId
WHERE id = (
(SELECT `users`.`id`
FROM `users`
WHERE (loginCount > 1000))
)
GROUP BY `id`
ORDER BY `age` DESC
So the way to go is break the entire query into individual queries first, and then construct the outer query. Just have patience and take it slow. That and read over the Zend_Db_Select docs to get a full picture of what you have available to you.

Categories