Codeigniter using Join or where to validate a row of result - php

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();

Related

How to sum a colum from a related model efficiently on Laravel

Ok I got this table
affiliates_referral_clicks
id | affiliate_id | clicks | date
1 | 1 | 10 | 2021-07-14
2 | 1 | 2 | 2021-07-11
3 | 2 | 1 | 2021-07-11
4 | 2 | 14 | 2021-07-10
...
Of course my Model Affiliate has a relationship with referralClicks
Affiliate.php
public function referralClicks(){
return $this->hasMany(AffiliateReferralClick::class,'affiliate_id');
}
Now I want to bring all Affiliates with the SUM of all their clicks that have a date between a given date. I implemented it like this
$affiliate = Affiliate::with(['referralClicks' => function($query) use($params) {
$query->whereDate('date','>=', $params['dateFrom'])
->whereDate('date','<=', $params['dateTo'])
->select('clicks')
;
}])->get();
foreach ($affiliates as $affiliate){
$affiliate->totalClicks = $affiliate->referralClicks->sum('clicks');
}
this works fine, but since the affiliates_referral_clicks table is waaaay too big and the request ends up being too slow, I think if you do the query without using Eloquent's helpers you can get a much faster query.
So my question would be...how can I do the same I just did but with raw querys (or whatever the most efficient way is)? Im using a MySQL DB I hope you guys can help me!
Haven't tried that yet but that's how I'd solve this (if we assume, you only need the sum and nothing else from the relationship):
$affiliate = Affiliate::withSum(['referralClicks.clicks as totalClicks' => function($query) use($params) {
$query->whereDate('date','>=', $params['dateFrom'])
->whereDate('date','<=', $params['dateTo'])
->select('clicks')
;
}])->get();

Doctrine Query how many times an Entity appears on other table

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();

need to get result of joining multiple tables as one row

I want to get result of joining multiple tables as one row and fetch multiple cuisine_name from t_cuisine table and get the cuisine_id in t_search.cuisineId column using php (CODEIGNITER) and joins
t_search table to get the cuisineId like this so that I can get the available cuisine names through the cuisineId.
t_search table
searchID|restaurant_name|cuisineId
1 | XYZ | 1,4,5
2 | KIH | 2
3 | GHY | 4,5
4 | UIO | 1,2,3
5 | RTY | 3,5
t_cuisine table
cuisineId|cuisine_name
1 | ABC
2 | CDE
3 | EFG
4 | GHZ
5 | HJL
in my Model i've used
$this->db->select('*');
$this->db->from('t_search');
$this->db->join('t_cuisine','t_cuisine.cuisineId = t_search.cuisineId');
which fetches data only based on single value in cuisineId in t_search.
$this->db->select('*');
$this->db->from('t_search');
$this->db->join('t_cuisine','t_cuisine.cuisineId IN(t_search.cuisineId)');
$this->db->where('t_cuisine.cuisineId', X);
Change X to the ID of the cuisine you are looking for
What you had previously (when your query worked based on a single value in cuisineId) was a one to many relationship. Joining like that worked well because each search had one cuisine.
This is a many to many relationship, and this table structure doesn't support it well. Instead of storing a delimited list in the cuisineId column of your t_search table, you need another table to represent the relationship between search and cuisine, like this:
t_search_cuisine table
searchID|cuisineId
1 | 1
1 | 4
1 | 5
2 | 2
3 | 4
3 | 5
4 | 1
4 | 2
4 | 3
5 | 3
5 | 5
Then you should be able to get all your data with one additional join.
$this->db->select('*');
$this->db->from('t_search');
$this->db->join('t_search_cuisine','t_search.searchID = t_search_cuisine.searchID');
$this->db->join('t_cuisine','t_search_cuisine.cuisineId = t_cuisine.cuisineId');
Based on the structure of your table, joining those table would be not easy. Perhaps you could do with two queries instead.
$this->db->select("cuisineId");
$this->where("searchID", $searchID);
$qry1 = $this->db->get("t_search");
$res1 = $qry1->row_array();
$qry1->free_result();
if ($res1) {
$this->db->select("*");
$this->db->where_in('cuisineId', $res1);
$qry2 = $this->db->get("t_cuisine");
$res2 = $qry2->result();
return ($res2) ? $res2 : false;
}

Codeigniter - Getting Value from a Secondary Table

I have 3 tables in my DB: ‘workouts’, ‘exercises’ and ‘exercise_list’.
workouts: | id | datetime | misc1 | misc2 |
exercises: | id | ex_id | wo_id | weight | reps | wo_order |
exercise_list: | id | title |
So far I have generated a view which grabs details of a specific workout (myurl.com/workouts/view/<datetime>)
I have built a query that grabs the fields from ‘workouts’ and also it grabs any ‘exercises’ entries that correspond to that workout (by get_where using wo_id).
I build a view which lists the exercises for that workout, but I can only get as far as foreach’ing out the ‘id’ of the exercise. I need to somehow have a further query that grabs the ‘title’ of each exercise that is associated with that workout ‘id’.
So I currently have a table (html):
| Exercise | Weight | Reps |
| 1 | 50 | 8 | ...
I need ‘1’ to become the title of the exercise in ‘exercise_list’ with an ‘id’ of ‘1’.
My solution
May not be perfect but it works:
public function get_exercises($wo_id)
{
$this->db->select('exercises.wo_id,
exercises.weight,
exercises.reps,
exercise_list.title');
$this->db->from('exercises');
$this->db->join('exercise_list','exercises.ex_id= exercise_list.id');
$this->db->where('exercises.wo_id',$wo_id);
$q = $this->db->get();
$query = $q->result_array();
return $query;
}
Not sure about the bestway to do the last few lines. This is in my model, so I needed to return the array. I am going tobet there is a way to do it better than the last 3 lines.
You can use joins and select title from your exercise_list table
$this->db->select('w.*,el.title')
->from('workouts w')
->join('exercises e','w.id = e.wo_id')
->join('exercise_list el','el.id = e.ex_id')
->where('e.wo_id',$yourid)
->get()
->result();

count with doctrine

I have two table:
Name
id | name | city_id
1 | aaa | 1
2 | vvv | 2
3 | ddd | 2
4 | sss | 3
5 | dds | 1
etc
City:
id | name
1 | London
2 | NY
3 | Boston
etc
how can i get City and count:
name_city | count
London | 2
NY | 2
Boston | 1
In City table:
$q = $this->createQuery('a')
->leftJoin('a.Name n')
->select('a.name_city as name_city, sum(n.city_id) as sum');
return $q->execute();
but this is wrong.
You should use count() instead of sum(), and plus, you need a group by.
You do not appear to have a FROM clause, the object type is not specified for the a entity.
Also, read the aggregate values section in the documentation.
this post was kinda helpful but I though that I would add a little more details for anyone looking to join 2 tables and with an aggregate count.
e.g. this post (http://stackoverflow.com/questions/7837671/mysql-join-tables-and-count-instances) but in doctrine.
Using the example above the query would be (doctrine 2.0):
$q = $this->em->createQueryBuilder('a')
->select('a.name_city as name_city, count(n.city_id) as sum');
->from('city','a')
->leftJoin('a.Name n')
->groupBy('n.id')
->orderBy('sum')
$query = $qb->getQuery();
echo $qb->getDql(); // if you want to see the dql created
$result = $query->getResult();

Categories