Suppose I have two tables:
Customer
id | name
1 | John
2 | Chris
Sales
id | client_id | price
1 | 1 | 100
2 | 1 | 200
3 | 1 | 300
4 | 2 | 150
5 | 2 | 250
The relationship between the tables is 1:M
What my query should look like if I want to return the data below?
client_name | number of sales
John | 3
Chris | 2
Right now my querybuilder looks like this, just a simple select *
$objs = $this->getDoctrine()->getManager()
->getRepository(Customer::class)
->createQueryBuilder('obj');
$objs = $objs->getQuery()->getResult();
Should I use some sort of join, or subquery? I would appreciate a little guidance, thank you.
Basically what #Arno Hilke wrote, but with some changes (and assuming your Customer entity is actually named Client):
$query = $this->getDoctrine()->getManager()
->getRepository(Client::class)
->createQueryBuilder('c')
->select('c.name as client_name, COUNT(s.client) as number_of_sales')
->join('c.sales', 's')
->groupBy('s.client')
->getQuery();
$result = $query->getArrayResult();
Join your sales table. Group by customers and count the occurrences of each customer. Something like this should work, depending on your exact entity definitions:
$query = $this->getDoctrine()->getManager()
->getRepository(Customer::class)
->createQueryBuilder('customer')
->select('customer.id as id, count(customer.id) as number');
->join('customer.sales', 'sales')
->groupBy('sales');
$result = $query->getQuery()->getArrayResult();
Thank you #Arno Hilke and #MichaĆ Tomczuk.
I changed the code a little to fit my needs. I needed some conditions in the select, so instead of COUNT I used SUM, the code ended like this:
$query = $this->getDoctrine()->getManager()
->getRepository(Customer::class)
->createQueryBuilder('c')
->select("c.name, SUM(CASE WHEN s.conditioneOne = 'valueOne' AND s.conditionTwo = 'valueTwo' THEN 1 ELSE 0 END) AS number_of_sales")
->join('c.sales', 's')
->groupBy('s.costumer')
->orderBy('number_of_sales', 'DESC');
$results = $query->getQuery()->getArrayResult();
Related
I have following table
users
id | username | password
1 | scott | 98746
2 | mark | 6542
3 | michel | 6589
user_detail
id | user_id | status | mobile_number
1 | 1 | pending | 987643210
2 | 2 | review | 3216547901
Now i want to retrieve those record where user has no records in user_detail table where status=pending
I have tried using relations in latest version
$user=User::with('userDetail')
->whereDoesntHave('userDetail',function ($query){
$query->where('status','pending');
})->get();
Same logic i am looking for without relations in laravel.Since we are using old laravel version which doesn't support.
I do not know what you mean by there are no relations, but if you have to do it with plain SQL, the query will look something like this:
$qry = "SELECT * FROM users WHERE id not in (SELECT u.id FROM users u INNER JOIN user_details d ON (u.id = d.user_id AND d.status = 'pending'));"
Then you can run the query by calling:
$results = DB::select($qry);
PS: Since I was not able to find it in the old docs, DB::select() may require 2nd param. If that is the case, just pass null as the second parameter.
EDIT:
I am not sure if this will work, and since it is for an old version, I am unable to test it, but something similar should work:
$rest = User::whereNotIn('id', function($q){
$q->select('user_id')->from('user_detail')->where('status','pending');
});
I believe you can do this by using left joins, something like this:
$rest = DB::table('users')
->leftJoin('userDetail','users.id','=','userDetail.user_id')
->whereNull('userDetail.id')
->orWhere('userDetail.status','=','pending')
->get();
If you need the eloquent collection of Users, you can use the hydrate method like this:
$rest = User::hydrate(DB::table('users')
->leftJoin('userDetail','users.id','=','userDetail.user_id')
->whereNull('userDetail.id')
->orWhere('userDetail.status','=','pending')
->select('users.*')
->get()->toArray());
cheers!
User table:
User_id(Pk,AI) | First_name | Last_name
1 | John | Doe
2 | Peter | Griffin
3 | Donald | Duck
Item table:
Item_id(PK,AI) | Owner(FK - user_id) | Item_name
1 | 1 | Shoes
2 | 2 | Pants
3 | 3 | Shirt
Item_review table:
Item_review_id(PK,AI) | Item(FK - item_id) | Reviewer(FK - user_id) | Rating |
Content
1 | 1 | 2 | 4 | Great
With the Tables above, There are three things i want to check before inserting a row into the review table.
Check if reviewer is not the item owner(cannot review own item or biased review)
Form validation(if reviewer inputted anything into the rating and content)
Check if review exists(no duplicate review or only one review per user)
That's my procedure, I've done the other two except the first one as i am unsure and confused on how to do this.
I could simply use a get where query like:
public function check_biased_review($user_id, $item_id){
$this->db->select('*');
$this->db->from('item');
$this->db->where('item_id', $item_id);
$this->db->where('owner', $user_id);
$query = $this->db->get();
if($query->num_rows() > 0){
return TRUE;}
else{
return FALSE;}
}
I actually solved this by writing the code above, i had this misconception that i would have to query so many rows if there are many reviews to find the matching rows that i forgot about the where clause in the first place which will do it in the db instead of doing it in the model function with an foreach loop and an if statement. I guess you have to code first instead of having assumptions and never doing it to check or you could waste time like i did.
But my first solution was to use a join query. $item_id and $user_id is passed from the controller to the model.
How would i go about joining the tables to get the same result?
I just try to give you an join query example below.
$this->db->select('*');
$this->db->from('Item_review');
$this->db->join('User','Item_review.user_id = User.User_id');
$this->db->join('Item','Item_review.item_id= Item.Item_id');
$this->db->where('item_id', $item_id);
$this->db->where('owner', $user_id);
$query = $this->db->get();
I have a table as illustrated below. How do I SELECT SUM column price WHERE type=1 AND type=2? I want the total of the price where type=1 and the total of the price where type=2 in just one query.
+-----+------+-------+
| PID | Type | Price |
+-----+------+-------+
| 1 | 1 | 100 |
| 2 | 2 | 65 |
| 3 | 1 | 300 |
| 4 | 1 | 200 |
| 5 | 2 | 50 |
+-----+------+-------+
I have tried this but it returns an error:
$this->db->select("SUM(price) as total1, (SELECT SUM(price) where type=2) as total2");
$this->db->from('table');
$this->db->where('type', '1');
$query = $this->db->get();
$result = $query->result();
I have also tried a few other ways of writing my query but to no avail, and all other ways I found in SO are too complicated and too much for my simple query. I think this should be a very simple query.
$sql=select price from table where type=1";
$exesql=mysqli_query($sql) or die(mysqli_error());
while($row=mysql_fetch_array($exesql)){
$tpeOneprice=$tpeOneprice+$row['price'];
}
echo $tpeOneprice;
do this to the type 2 also just like this.
Try this:
$this->db->select("SUM(price) as total1, (SELECT SUM(price) from table where type=2) as total2");
$this->db->from('table');
$this->db->where('type', '1');
$query = $this->db->get();
$result = $query->result();
I just tried in mysql.
Try this:
SELECT type, SUM(price) FROM test GROUP BY type
In my opinion group by is best option(options 2) for your requirement.
Option 1 :
$query = $this->db->query("select SUM(CASE WHEN type= '1' then 1 else 0 end) as total1, SUM(CASE WHEN type= '2' then 1 else 0 end) as total2 from table");
$result = $query->result();
PS: You can also use group by on type column.
With Group By (Option 2) :
$this->db->select("SUM(type)");
$this->db->from('table');
$this->db->group_by('type');
$query = $this->db->get();
$result = $query->result();
This will give you your two totals:
SELECT
SUM(IF(type=1,price,0)) AS Total1,
SUM(IF(type=2,price,0)) AS Total2
FROM table
WHERE type in (1,2)
I have two tables .
pre_order
receive_pre_order
My Question is how to get all the information from pre_order table and get the SUM of all the quantity received form receive_pre_order table against that pre_order id.
To make it clear suppose we have the following data in recieve_pre_order .
+--------------+------------+-------------------+
| pre_order_id | product_id | quantity_recieved |
+--------------+------------+-------------------+
| 1 | 1 | 10 |
| 1 | 1 | 20 |
| 1 | 1 | 10 |
+--------------+------------+-------------------+
It should return quantity_recieved = 40 against pre_order_id 1 .
Right now I have tried:
$this->db->select_sum('quantity_recieved');
$this->db->from('recieve_pre_order');
return $this->db->get();
It is working but, it is getting data from one table.
But I want to fetch data from both tables.
Join the two tables tables (rpo.pre_order_id = po.id). Group the result for po.id, so all Rows with the same po.id will be grouped into one row. sum(rpo.quantity_recieved) will sum up the quantity for these groups.
select po.id, sum(rpo.quantity_recieved)
from receive_pre_order rpo
join pre_order po on rpo.pre_order_id = po.id
group by po.id;
try this
$this->db->select("sum(recieve_pre_order.quantity_recieved),pre_order.id");
$this->db->from('recieve_pre_order');
$this->db->join("pre_order",'recieve_pre_order.pre_order_id = pre_order.id','left outer');
$this->db->where('recieve_pre_order.pre_order_id',your parameter);
$this->db->select('pre_order.*');
$this->db->select_sum('recieve_pre_order.quantity_recieved');
$this->db->from('pre_order');
$this->db->join("recieve_pre_order",'recieve_pre_order.pre_order_id = pre_order.id','left');
try sub query instead of joining table.
$this->db->select("po.*,SELECT(SUM(quantity_recieved) from receive_pre_order where pre_order_id = po.id) as total_recieved_quantity",FALSE);
$this->db->from('pre_order as po');
return $this->db->get();
I've two Collections and I want merge it to one variable (of course, with ordering by one collumn - created_at). How Can I do that?
My Controllers looks that:
$replies = Ticket::with('replies', 'replies.user')->find($id);
$logs = DB::table('logs_ticket')
->join('users', 'users.id', '=', 'mod_id')
->where('ticket_id', '=', $id)
->select('users.username', 'logs_ticket.created_at', 'action')
->get();
My Output looks for example:
Replies:
ID | ticket_id | username | message | created_at
1 | 1 | somebody | asdfghj | 2014-04-12 12:12:12
2 | 1 | somebody | qwertyi | 2014-04-14 12:11:10
Logs:
ID | ticket_id | username | action | created_at
1 | 1 | somebody | close | 2014-04-13 12:12:14
2 | 1 | somebody | open | 2014-04-14 14:15:10
And I want something like this:
ticket_id | table | username | message | created_at
1 |replies| somebody | asdfghj | 2014-04-12 12:12:12
1 | logs | somebody | close | 2014-04-13 12:12:14
1 | logs | somebody | open | 2014-04-14 11:15:10
1 |replies| somebody | qwertyi | 2014-04-14 12:11:10
EDIT:
My Ticket Model looks that:
<?php
class Ticket extends Eloquent {
protected $table = 'tickets';
public function replies() {
return $this->hasMany('TicketReply')->orderBy('ticketreplies.created_at', 'desc');
}
public function user()
{
return $this->belongsTo('User');
}
}
?>
A little workaround for your problem.
$posts = collect(Post::onlyTrashed()->get());
$comments = collect(Comment::onlyTrashed()->get());
$trash = $posts->merge($comments)->sortByDesc('deleted_at');
This way you can just merge them, even when there are duplicate ID's.
You're not going to be able to get exactly what you want easily.
In general, merging should be easy with a $collection->merge($otherCollection);, and sort with $collection->sort();. However, the merge won't work the way you want it to due to not having unique IDs, and the 'table' column that you want, you'll have to make happen manually.
Also they are actually both going to be collections of different types I think (the one being based on an Eloquent\Model will be Eloquent\Collection, and the other being a standard Collection), which may cause its own issues. As such, I'd suggest using DB::table() for both, and augmenting your results with columns you can control.
As for the code to achieve that, I'm not sure as I don't do a lot of low-level DB work in Laravel, so don't know the best way to create the queries. Either way, just because it's looking like starting to be a pain to manage this with two queries and some PHP merging, I'd suggest doing it all in one DB query. It'll actually look neater and arguably be more maintainable:
The SQL you'll need is something like this:
SELECT * FROM
(
SELECT
`r`.`ticket_id`,
'replies' AS `table`,
`u`.`username`,
`r`.`message`,
`r`.`created_at`
FROM `replies` AS `r`
LEFT JOIN `users` AS `u`
ON `r`.`user_id` = `u`.`id`
WHERE `r`.`ticket_id` = ?
) UNION (
SELECT
`l`.`ticket_id`,
'logs' AS `table`,
`u`.`username`,
`l`.`action` AS `message`,
`l`.`created_at`
FROM `logs` AS `l`
LEFT JOIN `users` AS `u`
ON `l`.`user_id` = `u`.`id`
WHERE `l`.ticket_id` = ?
)
ORDER BY `created_at` DESC
It's pretty self-explanatory: do the two queries, returning the same columns, UNION them and then sort that result set in MySQL. Hopefully it (or something similar, as I've had to guess your database structure) will work for you.
As for translating that into a Laravel DB::-style query, I guess that's up to you.