codeigniter database query / mysql - php

I have written a query with codeigniters database library, it looks like this,
public function getCandidateCredits($candidate_id)
{
$this->db->select('*')
->from('credits')
->join('candidate_has_credits', 'candidate_has_credits.credits_credit_id = credits.credit_id', 'left')
->where('credits.candidates_candidate_id', (int)$candidate_id)
->order_by('candidate_has_credits.date_created', 'DESC')
->order_by('credits.credit_position', 'DESC');
$query = $this->db->get();
return $query->result_array();
}
What this query is meant to do is, get all a members credits, and the order them firstly by date (newest first), then by credit position (highest number first).
I am having a couple of problems though, the credits should be ordered by date, but only if there is no credit position, if there is a credit position (0 - 999) then that should take precendence where ordering the credits, if there is a date and a credit position then the credits should be ordered by credit position and then date.
Is this possible? I feel like I am miles away from where I need, the results I return seem to be return no obvious ordering. Not sure if it makes a difference but the date_created field is a DATETIME.

You are correctly using a left join, but have put the order by clauses in the wrong order, so first of all, flip them:
->order_by('credits.credit_position', 'DESC')
->order_by('candidate_has_credits.date_created', 'DESC')
This should do it, except that now those candidate_has_credit rows that do not have corresponding credits records (so the credit_position is null) will be in the end, and I assume you want those on top.
There is a small trick to push null values to top when using DESC sorting providing you know the maximum value available in that field:
->order_by("ifnull('credits.credit_position',1000) desc,candidate_has_credits.date_created desc")
Note that I am using the form of order_by method which contains only one parameter, that one should not escape the function and is marginally faster.
Check the ifnull documentation to see how it works.

Here's a shortened version:
public function getCandidateCredits($candidate_id)
{
return $this->db->from('credits')
->join('candidate_has_credits', 'candidate_has_credits.credits_credit_id = credits.credit_id', 'left')
->where('credits.candidates_candidate_id', (int)$candidate_id)
->order_by('credits.credit_position', 'DESC')
->order_by('candidate_has_credits.date_created', 'DESC')
->get()->result_array();
}

Related

Refining My Eloquent Query (Laravel)

Edited for Clarity:
I need some way for this Query to only return distinct course_ids in the
->wherein('course_id', $array)
part of the query. It gets the total number of completed courses, but if a user has completed a course more than once it counts it toward the total. So if you want to know how many students have done a course, the number will be off if a student has completed a course more than once.
public function report_count(){
$array = \Session::get('course_report')['course'];
return $this->hasOne('Tracking', 'roster_id')
->selectRaw('roster_id, count(*) as aggregate')
->where('status', 1)
->wherein('course_id', $array)
->groupBy('roster_id');
I've tried adding groupBy('course_id') at the end but it does not work.
Fixed. Changed the query to
return $this->hasOne('Tracking', 'roster_id')
->selectRaw('roster_id, count(distinct course_id) as aggregate')
->where('status', 1)
->wherein('course_id', $array)
->groupBy('roster_id');
per #Robin R suggestion, I went on a search of ways to utilize SQL in my selectRaw query instead of trying this the eloquent way. Thanks to all who helped me brainstorm though this one.

Symfony Doctrine Query Builder Where last in arraycollection

I want to use symfony's query builder and add a where to the last item in an array collection
$query = $em->getRepository('RlBookingsBundle:Booking')->createQueryBuilder('b')
->select('b, v, c, ca, q')
->leftJoin('b.vehicle', 'v')
->leftJoin('b.customer', 'c')
->leftJoin('c.address', 'ca')
->leftJoin('b.quote', 'q')
->leftJoin('b.history', 'h') //This is an array collection
->orderBy('b.edited', 'DESC')
;
I want to use only the latest value from history as it is a log but only the most recent entry is valid
->where('h.status IN (:status)')
->setParameter('status', [7]);
Will return all results with h.status = 7 but I would like it to only query the most recent result. Is there anyway to do this?
I tried a groupby on the history field but this seems to groupby with data from the first entry, even if I add an orderby to it.
If the results you get are already ok, but you only want the first, you could just use
...
->setMaxResults(1)
...
If you want to order by history ID desc, you may want to add another orderBy clause before the existing one
...
->orderBy('h.id', 'DESC')
->orderBy('b.edited', 'DESC')
...
If it's more complex than that, I strongly suggest you perform a separate query to get the desired record(s) from history, and THEN use it as a filter, instead of the leftJoin.

Codeigniter join, group_by and max

I can't find a way to get it working. I have to tables, the first with orders and the second with trackings. I want to add the latest tracking row to left table row.
This is what I've tried so far (doesn't work):
$this->db->select('orders.*, trackings.id AS trackings_id, trackings.order_id AS trackings_order_id, MAX(trackings.status) AS trackings_status, trackings.created_at AS trackings_created_at, trackings.updated_at AS trackings_updated_at, trackings.ip_address AS trackings_ip_address');
$this->db->from('orders');
$this->db->join('trackings', 'orders.id = trackings.order_id', 'left');
$this->db->group_by('trackings.order_id');
$this->db->order_by('orders.created_at', 'DESC');
$query = $this->db->get();
return $query->result();
Woooh, I hate CI's active records, this is a real pain in the butt most of times...
First of all, I'd group by orders.id
Secondly, would be great if you'd define "not working" (gives wrong results? doesn't execute at all?)
P.S. Sorry for posting it as answer (I'd prefer comment) but my rep is still kinda low...

Order by multiple columns with Doctrine

I need to order data by two columns (when the rows have different values for column number 1, order by it; otherwise, order by column number 2)
I'm using a QueryBuilder to create the query.
If I call the orderBy method a second time, it replaces any previously specified orderings.
I can pass two columns as the first parameter:
->orderBy('r.firstColumn, r.secondColumn', 'DESC');
But I cannot pass two ordering directions for the second parameter, so when I execute this query the first column is ordered in an ascending direction and the second one, descending. I would like to use descending for both of them.
Is there a way to do this using QueryBuilder? Do I need to use DQL?
You have to add the order direction right after the column name:
$qb->orderBy('column1 ASC, column2 DESC');
As you have noted, multiple calls to orderBy do not stack, but you can make multiple calls to addOrderBy:
$qb->addOrderBy('column1', 'ASC')
->addOrderBy('column2', 'DESC');
In Doctrine 2.x you can't pass multiple order by using doctrine 'orderBy' or 'addOrderBy' as above examples. Because, it automatically adds the 'ASC' at the end of the last column name when you left the second parameter blank, such as in the 'orderBy' function.
For an example ->orderBy('a.fist_name ASC, a.last_name ASC') will output SQL something like this 'ORDER BY first_name ASC, last_name ASC ASC'. So this is SQL syntax error. Simply because default of the orderBy or addOrderBy is 'ASC'.
To add multiple order by's you need to use 'add' function. And it will be like this.
->add('orderBy','first_name ASC, last_name ASC'). This will give you the correctly formatted SQL.
More info on add() function. https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html#low-level-api
Hope this helps. Cheers!
you can use ->addOrderBy($sort, $order)
Add:Doctrine Querybuilder btw. often uses "special" modifications of the normal methods, see select-addSelect, where-andWhere-orWhere, groupBy-addgroupBy...
You can use orderBy() followed by an addOrderBy() - nesting several orderBy()'s is not possible, but nesting several addOrderBy()'s also works after the initial orderBy().
Example:
$this->createQueryBuilder('entity')
->orderBy('entity.addDate', 'DESC')
->addOrderBy('entity.id', 'DESC')
The orderBy method requires either two strings or an Expr\OrderBy object. If you want to add multiple order declarations, the correct thing is to use addOrderBy method, or instantiate an OrderBy object and populate it accordingly:
# Inside a Repository method:
$myResults = $this->createQueryBuilder('a')
->addOrderBy('a.column1', 'ASC')
->addOrderBy('a.column2', 'ASC')
->addOrderBy('a.column3', 'DESC')
;
# Or, using a OrderBy object:
$orderBy = new OrderBy('a.column1', 'ASC');
$orderBy->add('a.column2', 'ASC');
$orderBy->add('a.column3', 'DESC');
$myResults = $this->createQueryBuilder('a')
->orderBy($orderBy)
;
The comment for orderBy source code notes: Keys are field and values are the order, being either ASC or DESC.. So you can do orderBy->(['field' => Criteria::ASC]).

Kohana orm order asc/desc?

I heed two variables storing the maximum id from a table, and the minimum id from the same table.
the first id is easy to be taken ,using find() and a query like
$first = Model::factory('product')->sale($sale_id)->find();
but how can i retrieve the last id? is there a sorting option in the Kohana 3 ORM?
thanks!
Yes, you can sort resulting rows in ORM with order_by($column, $order). For example, ->order_by('id', 'ASC').
Use QBuilder to get a specific values:
public function get_minmax()
{
return DB::select(array('MAX("id")', 'max_id'),array('MIN("id")', 'min_id'))
->from($this->_table_name)
->execute($this->_db);
}
The problem could actually be that you are setting order_by after find_all. You should put it before. People do tend to put it last.
This way it works.
$smthn = ORM::factory('smthn')
->where('something', '=', something)
->order_by('id', 'desc')
->find_all();
Doing like this, I suppose you'll be :
selecting all lines of your table that correspond to your condition
fetching all those lines from MySQL to PHP
to, finally, only work with one of those lines
Ideally, you should be doing an SQL query that uses the MAX() or the MIN() function -- a bit like this :
select max(your_column) as max_value
from your_table
where ...
Not sure how to do that with Kohana, but this topic on its forum looks interesting.

Categories