I am writing a query in DQL where I want to select the latest order from a customer. Currently I only managed to get all the orders and get them based on their date in a descending order. Which means I need to filter it to go per user as well as just pick their latest entry. However , my knowledge of DQL and queries in general isn't that high I am stuck. Any help on how to continue my query would be appreciated.
public function getLatestOrder($customer){
// get the latest order from a customer
$em = $this->getEntityManager();
$q1 = $em->getRepository('AppBundle:Order')->createQueryBuilder('o')
->leftjoin("AppBundle:User", "u")
->where("u.id = :customer_user_id")
->setParameter('customer_user_id', $customer)
->orderBy('o.date', 'DESC' );
$q1 = $q1->getQuery();
$res1 = $q1->getResult();
return $res1;
}
Additional info: The order entity has a customer column which refers to the user info.
Instead of join better you can use sub queries.
You can try this:
$em->getRepository('AppBundle:Order')->createQueryBuilder('o')
->leftjoin("AppBundle:User", "u")
->leftjoin("AppBundle:Order", "laterOrder", 'WITH', 'laterOrder.date > o.date')
->where("u.id = :customer_user_id")
->andWhere("laterOrder is null")
Related
I have the following two queries. The first query is fetching a key called srNumber from first table called tags and then the second query is using that srNumber to fetch details from a second table called nexttable.
$tagQuery = "SELECT * FROM tags WHERE status = 0 AND currentStage = '1' AND assignedTo = '1' ORDER BY
deliveryDate ASC";
$tagQueryExecute = mysqli_query($conn, $tagQuery);
while($rows = mysqli_fetch_array($tagQueryExecute)){
$srNumber = $rows['srNumber'];
$nextQuery = "SELECT * FROM nexttable WHERE srNumber='$srNumber'";
$nextQueryExecute = mysqli_query($conn, $nextQuery);
$detailsFromNextTable = mysqli_fetch_array($nextQueryExecute);
//Show these details
}
For a small result this is not a big issue. But if the first query got so many results, then second query has to run as many times as number of loop. Is there any other way to do this efficiently?
NB: Please ignore the SQL injection issues with these queries. I just simplified it to show the problem
As you appear to have only 1 row in the second table, you would be better off with a join, MySQL: Quick breakdown of the types of joins gives some more info on the types of joins.
SELECT *
FROM tags t
JOIN nexttable n on t.srNumber = n.srNumber
WHERE t.status = 0 AND t.currentStage = '1' AND t.assignedTo = '1'
ORDER BY t.deliveryDate ASC
This also removes the SQL injection as well.
I would also recommend removing the * and just list the columns you intend to use, this also helps if you have columns with the same names in the different tables as you can add an alias to the specific columns.
FYI - the original problem you have is similar to What is the "N+1 selects problem" in ORM (Object-Relational Mapping)?
Ok I have a flag field on one table, open or closed which is boolean. I am trying to build one query that would take that field and count them based on that flag. Then I will need to group them by account ID
Here is what I am working with now,
$GetTest1 = $GetRepo->createQueryBuilder('s') <- I had 'w' in here but all that did was add an index and not a second alias?
->select(' (count(s.open_close)) AS ClosedCount, (count(w.open_close)) AS OpenCount ')
->where('s.open_close = ?1')
//->andWhere('w.open_close = ?2')
->groupBy('s.AccountID')
->setParameter('1', true)
//->setParameter('2', false)
->getQuery();
Is what I want do-able? I know (or at lest think) that I can build a query with multiple table alias? - Please correct me if I am wrong.
All help most welcome.
Thanks
This DQL query will group the rows in table by accountId and for each of them it will give you count for yes (and you can get count for no by substracting that from total).
BTW I found writing straight DQL queries much more straightforward than writing QueryBuilder queries (which i use only when i need to dynamically construct the query)
$results = $this->get("doctrine")->getManager()
->createQuery("
SELECT t.accountId, SUM(t.openClose) as count_yes, COUNT(t.accountId) as total
FROM AppBundle:Table t
GROUP BY t.accountId
")
->getResult();
foreach ($results as $result) {
//echo print_r($result);
//you can get count_no as $result["total"] - $result["count_yes"];
}
I have 2 tables, one is called post and one is called followers. Both tables have one row that is called userID. I want to show only posts from people that the person follows. I tried to use one MySQL query for that but it was not working at all.
Right now, I'm using a workaround like this:
$getFollowing = mysqli_query($db, "SELECT * FROM followers WHERE userID = '$myuserID'");
while($row = mysqli_fetch_object($getFollowing))
{
$FollowingArray[] = $row->followsID;
}
if (is_null($FollowingArray)) {
// not following someone
}
else {
$following = implode(',', $FollowingArray);
}
$getPosts = mysqli_query($db, "SELECT * FROM posts WHERE userID IN($following) ORDER BY postDate DESC");
As you might imagine im trying to make only one call to the database. So instead of making a call to receive $following as an array, I want to put it all in one query. Is that possible?
Use an SQL JOIN query to accomplish this.
Assuming $myuserID is an supposed to be an integer, we can escape it simply by casting it to an integer to avoid SQL-injection.
Try reading this wikipedia article and make sure you understand it. SQL-injections can be used to delete databases, for example, and a lot of other nasty stuff.
Something like this:
PHP code:
$escapedmyuserID = (int)$myuserID; // make sure we don't get any nasty SQL-injections
and then, the sql query:
SELECT *
FROM followers
LEFT JOIN posts ON followers.someColumn = posts.someColumn
WHERE followers.userID = '$escapedmyuserID'
ORDER BY posts.postDate DESC
I am building a Twitter-like application which has a feed in it. In this feed I need to display shares with this properties:
-Shares from user, who I am following
-Shares from user, which are sorted by the positive rating, but only the top10%
These two queries I need somehow to merge, so it will become an array in the end, which has all the shares which are applying to this criteria, without any duplicates and ordered by ID, desc
My tables are looking like this:
User, Shares, Follows
Shares:
-user_id
-positive
Follows:
-follower_id
-user_id
-level
What I already tried:
$follower_shares = Share::join('follows', 'shares.user_id', '=', 'follows.user_id')
->where('follows.follower_id', Auth::user()->id)
->where('follows.level', 1)
->get(array('shares.*'));
//count = 10% of total shares
$count = Share::count()/10;
$count = round($count);
$top10_shares = Share::orderBy('positive', 'DESC')
->take($count)
->get();
//sorts by id - descending
$top10_shares = $top10_shares->sortBy(function($top)
{
return -($top->id);
});
//merges shares
$shares = $top10_shares->merge($follower_shares);
The problem is now, that I was told that there is a better way to solve this.
Also, $shares is giving me the result which applies to the criteria, but the shares have duplicates (rows, which are applying to both criteria) and arent ordered by id desc in total.
I would be very happy, if you could tell me, how to do this the right way.
Thanks very much!
I found this to be a pretty clean solution:
// Instead of getting the count, we get the lowest rating we want to gather
$lowestRating = Share::orderBy('positive', 'DESC')
->skip(floor(Share::count() * 0.1))
->take(1)->lists('positive');
// Also get all followed ids
$desiredFollow = Auth::user()->follows()->lists('user_id');
// Select where followed or rating higher than minimal
// This lets the database take care of making them distinct
$shares = Share::whereIn('user_id', $desiredFollow)
->orWhere('positive', '>=', $lowestRating[0])
->get();
I have a table with this structure:
opinion_id, author_id, title, content
I would like to get all the latest records from the table, one record for author, that means the latest record for every author...
My distinct function does not seem to be working...
function getOpinions() {
$data = array();
$this->db->select('*');
$this->db->from('opinions');
$this->db->join('authors', 'opinions.author_id = authors.author_id');
$this->db->order_by('date', 'desc');
$this->db->distinct('author_id');
$Q = $this->db->get();
if ($Q->num_rows() > 0) {
foreach($Q->result_array() as $row) {
$data[] = $row;
}
}
$Q->free_result();
return $data;
}
In Codeigniter, distinct does not work the way you expect it by field name. If you look at the manual - there is no argument for distinct. If you look at the code, it only takes a boolean, which defaults to true. It just adds the DISTINCT keyword to the query after the SELECT keyword. That's it.
In your case, I think it would be better to use a GROUP BY as in
$this->db->group_by('opinions.author_id');
Hopefully the order by would work as per your need in this instance by ordering before the grouping.
Cheers!
EDIT - update after OP comments
I know the ordering can be messed up - I sort of mentioned it :)
Anyway, I might be assuming some of your table structure here, but this would force the GROUP BY to pick the rows on the top. I assume that the date is on the opinions table and you only want the latest row from that with author details.
SELECT * FROM `authors`
JOIN (
SELECT * FROM opinions
ORDER BY `date` DESC
) AS ops ON ops.author_id = authors.author_id
GROUP BY ops.author_id
You will not be able to construct this query on active record though. Hope this helps.