Doctrine orWhere for multiple columns - mysql

I need to fetch using doctrine, my entity has three date values, expiryDate, scheduledDate, addedDate(mandatory). I need to check first is there any row having scheduledDate as today , If no then I need to check for entry before expiryDate which has the latest addedDate.
I try this code ,
public function getLatestEntry(){
$today = date("Y-m-d");
$qb = $this->em->createQueryBuilder();
$qb ->select('MyEntry')
->from('MyEntry', 'myEntry')
->Where('myEntry.scheduledOn = :today')
->orWhere('myEntry.expirationDate >= :today')
->orWhere('myEntry.expirationDate is null')
->orderby('myEntry.addedDate')
->setMaxResults(1)
->setParameters(array('today' => $today));
return $qb->getQuery()->getResult();
}
But I didn't get the result I expected ,I feel like the first where condition has been ignored, How can I tackle this?

Right now you have 3 conditions with equal priority. If one of these is true the row is fetched. But you want your conditions with different priorities. Either the first one matches or it does not match and second matches. Not that your third condition is part of your second one:
$qb ->select('MyEntry')
->from('MyEntry', 'myEntry')
->Where('myEntry.scheduledOn = :today')
->orWhere('(myEntry.scheduledOn != :today AND (myEntry.expirationDate >= :today OR myEntry.expirationDate IS NULL))')
->orderby('myEntry.addedDate')
->setMaxResults(1)
->setParameters(array('today' => $today));
EDIT:
I'm not quite shure if you want to have entries with expiration date NULL equally treated as the ones with an expiration date set. If its not equal for you, you could alter your ORDER BY clause like
->orderby('myEntry.addedDate', 'ASC')
->addOrderBy('my.Entry.expirationDate', 'DESC')

Related

How to count all records if use alias in select query?

I use Sphinx with Yii2 and need to query with filter by jSON field.
$query = new \yii\sphinx\Query();
$query->from('announcements');
$query->addSelect("*");
$query->addSelect(new Expression("IN(filters['color'], 'blue', 'red', 'green') AS f_color"));
$query->where("is_active = 1");
$query->andWhere("f_color = 1");
$announces = $query->all();
There is jSON field filters in my Sphinx index. For example:
[filters] => {"brand":"Toyota","model":"Prius","color":"red","price":"12000"... etc]
It works OK. But now I need to make a pagination... and there is a problem when I try to count records before $query->all()
$count = $query->count(); // Return error "no such filter attribute 'f_color'"
Generated query was:
SELECT COUNT(*) FROM announcements WHERE ( is_active = 1 ) AND ( f_color = 1 )
count() by default replaces the select part with * and this is where your alias is defined hence the error.
There are different ways to achieve it like:
use ActiveDataProvider like described here,
use META information like described here
Since you want to make a pagination I would go with the first example.

Laravel QueryBuilder - Different result with `where()` and `whereRaw()` for the identical Query

I'm working on a laravel application Where I have two very similar QueryBuilder but producing different result in both conditions.
Query 1:
$ids = $this->model->leftJoin('feed', 'agents.identifier', '=', 'feed.identifier')
->whereRaw('feed.active <> agents.feed_status')
->pluck('id');
dd(count($ids)); // print 485236
Query 2:
$ids = $this->model->leftJoin('feed', 'agents.identifier', '=', 'feed.identifier')
->where('feed.active', '<>', 'agents.feed_status')
->pluck('id');
dd(count($ids)); // print 4259
I would like to know the key difference between these two QueryBuilder. Why is it producing different results, although it seems identical?
And which query returns the correct result? if I would like to find the records from agents where feed_status is not equel to feed.active.
it seem I have got the clarification. Howevere I would like to share my R&D here. Incase if anyone else got the same problem.
I have printed the raw query and get where() seems consider the third parameter as string compare instead of field compare. That's why seems the result is different.
However when we run the query with whereRaw() it's treated this as table field comparision.
Laravel Code:
$ids = $this->model->leftJoin('feed', 'agents.identifier', '=', 'feed.identifier')
->whereRaw('feed.active <> agents.feed_status')
->pluck('id');
MySql Query:
"select * from `agents` left join `feed` on `agents`.`identifier` = `feed`.`identifier` where feed.active <> agents.feed_status"
# where feed.active <> agents.feed_status
Laravel Code:
$ids = $this->model->leftJoin('feed', 'agents.identifier', '=', 'feed.identifier')
->where('feed.active', '<>', 'agents.feed_status')
->pluck('id');
MySql Query:
"select * from `agents` left join `feed` on `agents`.`identifier` = `feed`.`identifier` where `feed`.`active` <> 'agents.feed_status'"
# where feed.active <> 'agents.feed_status'
Yes, the results were meant to be different.
As where method compares a column with a literal value
->where('table.column', 'cond', 'value')
If you are looking to make comparisons in two columns without using whereRaw method; you should instead use whereColumn method
->whereColumn('table1.column1', 'cond', 'table2.column2')

Count a field in database

I want to count a field name 'leave_policy' depending on the name of 'leave_policy' and I am using joins to do it. My database is like this
https://imgur.com/a/gR3Dw
and I want to show count in applied section. For example if I want to count all "Urgent Leaves" and "Paternal Leaves" seperately I have applied till now. https://imgur.com/a/dvjuX
$join = DB::table('leaves_policy')
->join('leaves_policies', 'leaves_policy.leave_policy', '=', 'leaves_policies.title')
->join('leaves_requests', 'leaves_policy.requested_by' , '=', 'leaves_requests.requested_by')
->select('leaves_policy.*', 'leaves_policies.title', 'leaves_policies.total_no_of_leaves_allowed_per_year',
'leaves_policies.no_of_months_leaves_valid', 'leaves_policies.max_leaves_per_month', 'leaves_policies.max_con_leaves_per_month',
'leaves_requests.leave_status', DB::raw('COUNT(leaves_policy.leave_policy) as count'))
->groupBy('id')
->get();
For example,
I have a table Leave_table. leave_policy and purpose are the fields.
I am displaying the leave count based on the leave_policy column. i have used the below query to get the count.
select leave_policy,count(leave_policy) from leave_table group by leave_policy

Compare two dates in a database table are equal

I'm new here. So, be easy on me. I have a table called 'data' in which one of the columns is 'date' stored in YYYY-MM-DD format. Here is the code that I have been working on. Basically, what I want to do is compare if two dates stored in my table are equal. But, each time I run the code, I keep getting error: Undefined offset right where the code says $lisdate[$i+1]. How do I compare the dates stored in a table? Thank you.
My code
$sth2 = mysql_query("SELECT * FROM data WHERE dest_name='www.myren.net.my'");
while($rowstemp = mysql_fetch_assoc($sth2))
{
$lisdate[] = $rowstemp['date'];
$lisaverage[] = $rowstemp['avg_rtt'];
}
$rows = mysql_num_rows($sth2);
$addAverage[0] = $lisaverage[0];
$numbers = 0;
$j = 0;
for($i = 0; $i<$rows; $i++)
{
if($lisdate[$i] == $lisdate[$i+1])
{
$addAverage[$j] = $addAverage[$j] + $lisaverage[$i+1];
}
else
{
$j++;
$numbers = $numbers +1;
}
}
Gordon has it right. Your for loop is overrunning the end of your array because you're working with consecutive pairs of rows. Change it to read ; $i < $rows - 1; to correct this problem.
But, you have another problem. SQL rows in result sets have an unpredictable order unless your query includes an ORDER BY clause. If these rows, without that clause, appear in ascending order by date, it's dumb luck. Put ORDER BY date in your query.
It's not entirely clear what that code in the question is attempting to achieve.
(As Ollie pointed out in his answer, it bears repeating: the order that MySQL returns the rows is guaranteed ONLY if there's an ORDER BY clause on the query. The result from a "duplicate date" check that's being performed in the code is only going to detect a "duplicate" date value if it appears on contiguous rows.)
We see the code loading a couple of arrays, using the date and avg_rtt column values returned by the query. Then there's some manipulation on the array... the end result will be another it's not clear what the actual intent of that rigmarole is, what it's actually trying to achieve.
If there are any rows It looks like there's going to be another array... if there are no "duplicate" date values found, it's going to have a single element (with the value of rtt_avg from the first row), and $numbers will be set to the number of elements in the original array.
If there is a "duplicate" date values found, the results from the code seem very odd to me, a sparsely populated array. Why?
Personally, I'd be looking to get an actual statement of the specification, and have the database do that processing for me, rather than mucking through two arrays.
If what we want is set of values with no duplicated date values, I'd use a GROUP BY and some aggregation, for example:
SELECT d.dest_name
, d.date
, AVG(d.avg_rtt) AS avg_avg_rtt
, MAX(d.avg_rtt) AS max_avg_rtt
, MIN(d.avg_rtt) AS min_avg_rtt
, SUM(d.avg_rtt) AS sum_avg_rtt
, COUNT(1) AS cnt
, COUNT(d.avg_rtt) AS cnt_avg_rtt
, COUNT(DISTINCT d.avg_rtt) AS cnt_distinct_avg_rtt
FROM data d
WHERE d.dest_name = 'www.myren.net.my'
GROUP
BY d.dest_name
, d.date
ORDER
BY d.dest_name
, d.date
If I was looking for just a count of distinct date values, like what $numbers is going to contain, then just:
SELECT d.dest_name
, COUNT(DISTINCT d.date) AS cnt_distinct_date
FROM data d
WHERE d.dest_name = 'www.myren.net.my'
GROUP BY d.dest_name
ORDER BY d.dest_name
The "looping through array" that the original query just looks like an odd way to achieve a result, whatever that result is supposed to be.

MySQL group by DAY in same table not working when count zero

My following query not return row when COUNT(*) result return 0 row
SELECT COUNT(id) test,
UNIX_TIMESTAMP(my_time)*1000 d
FROM chat_table
WHERE dept_id = 5
AND my_time >="2015-03-30"
GROUP BY DAY(my_time)
ORDER BY d ASC;
I need GROUP BY day even return 0 row. How can left join in same table? or any idea?
You can only have groups based on values that exist. If a value, for example, timestamp '2015-04-01 12:00:00' does not exist in your table, it cannot be part of the result.
You can work around this by:
handling the results of the query in a programming language, supplementing count 0 for all rows that are missing
OR creating a reference table that contains all timestamps
OR manually injecting all timestamps using a subquery and union.
The best option is the first: keep your query as it is, but write logic in the program that starts the query to automatically assume that the count is zero if the timestamp is not in the result set.
For example, in PHP:
$countsPerTimestamp = array();
foreach ($stmt->fetchAll() as $row) {
$countsPerTimestamp[$row['d']] = $row['test'];
}
$searchTimestamp = '2015-04-05 12:13:14';
if (isset($countsPerTimestamp[$searchTimestamp])) {
echo 'Count for now is: ' . $countsPerTimestamp[$searchTimestamp];
}
else {
echo 'Count for now is: 0';
}
If your table has data on every day but the where clause is filtering it out, then the easiest solution is to use conditional aggregation:
SELECT SUM(dept_id = 5) as test,
UNIX_TIMESTAMP(my_time)*1000 as d
FROM chat_table
WHERE my_time >= '2015-03-30'
GROUP BY DAY(my_time)
ORDER BY d ASC;
If those conditions are not true, then you need to start with a list of all the dates and use left join.