I have three tables Beneficiary, Questions, Responses..Beneficiary
Benficiary
id name
1 user1
2 user2
3 user3
Questions
id question type
1 what is your hobby hobby
2 address contact
3 phone contact
..questions upto 500 and i need to select according to its type
Response
id beneficiary_id question_id response
1 1 1 football
2 1 3 5354353
3 2 1 basketball
4 3 2 cityname
5 3 3 432423
Beneficiary table and Question table are static but response table joins both of them. I tried to do this from laravel query but it gives me only responses
sql query
select response,questions.question, beneficiarys.name
from responses RIGHT join (questions,beneficiarys)
on beneficiarys.id = responses.beneficiary_id && questions.id = responses.question_id
where questions.sheet_type = 'SCDS' OR questions.sheet_type = 'SMM'
laravel query
$beneficiaries = Beneficiary::with('quests','response')->whereHas('response', function ($query)use($sheet_type) {
$query->where('beneficiary_id', '>', 0);
})
->whereHas('quests',function($query)use($sheet_type){
$query->where('questions.sheet_type','=',$sheet_type);
$query->orWhere('questions.sheet_type','=','SCDS');
})
->where('updated_at','>=',!empty($this->request->from_date)?$this->request->from_date:$from)->where('updated_at','<=',!empty($this->request->to_date)?$this->request->to_date:$date)->get();
Beneficiary Model
public function response()
{
return $this->hasMany('App\Model\Response');
}
public function quests(){
return $this->belongsToMany('App\Model\Question', 'responses','beneficiary_id','question_id');
}
Question Model
public function response(){
return $this->hasMany('App\Model\Response');
}
public function bens(){
return $this->belongsToMany('App\Model\Bebeficiary', 'responses','question_id','beneficiary_id');
}
Response Model
public function beneficiary(){
return $this->belongsTo('App\Model\Beneficiary', 'beneficiary_id');
}
public function question(){
return $this->belongsTo('App\Model\Question', 'question_id');
}
I need all the question according to its type(type is selected by user from view) and i need output like this
beneficary hobby address phono ....
user1 football null 4244 ....
user2 basketball null null ....
is there any way to achieve it with sql or laravel query*
this is the mysql select, maybe is a better way to it but this work
SELECT b.name,hobby.response as hobby,address.response as addres,phone.response as
phone FROM beneficiary as b
left join (select * from response where question_id=1 ) as hobby
on hobby.beneficiary_id = b.id
left join (select * from response where question_id=2 ) as address
on address.beneficiary_id = b.id
left join (select * from response where question_id=3 ) as phone
on phone.beneficiary_id = b.id
You Will get result from this query. Laravel Support customization as well.
$sSQL = "SELECT * FROM RESPONSE
INNER JOIN QUESTION ON QUESTION.id=RESPONSE.QUESTION_id
INNER JOIN BENEFICIARY ON BENEFICIARY.id=RESPONSE.BENEFICIARY_id";
DB::query($sSQL);
Try
$res = DB::table('responses')
->join('questions','responses.question_id','=','questions.id')
->join('beneficiarys','responses.beneficiary_id','=','beneficiarys.id')
->select('responses.*','questions.question','beneficiarys.name')
->where('questions.sheet_type', '=','SCDS')
->orWhere('questions.sheet_type','=','SMM')
->get();
Use the result as
foreach($res as $res)
{
echo $res->name;
}
If you want to do it Eloquent way you could try using whereHas on your nested relationships. Try something like :
Beneficiary::with('response.question')->whereHas('response.question')
For more references try this link Eloquent with nested relationships
Related
Till know I join 3 table
$this->db->select('*');
$this->db->from('dispatch_challan');
$this->db->join('challan_bilties', 'dispatch_challan.disp_id = challan_bilties.challan_id');
$this->db->join('bilty', 'challan_bilties.challan_bilties_id = bilty.id');
$this->db->where('dispatch_challan.disp_ch_no',$disp_ch_no);
$query = $this->db->get();
return $query->result_array();
My output is like this after join table
In above image the Consignor and Consignee fetch id but i want name so i want to join 4th table i.e ts_users
In this table the full name of this Consignor and Consignee
ts_users table
user_id user_fullname user_remark
1 abc consignee
2 xyz consignor
3 pqr consignee
4 lmn consignor
I want to get full name based on Consignor and Consignee from 4th table(ts_users)
Since you don't really tell us where the consignor and consignee fields come from, you'll need to fill in the blanks (denoted as xxx below)
All you need is to join twice with the ts_users table. Add these:
$this->db->join('ts_users u1', 'xxx.consignor = u1.user_id');
$this->db->join('ts_users u2', 'xxx.consignee = u2.user_id');
Since you'll be joining twice with the same table, your resultset will be a bit confusing if you stick to select * so I'd recommend fetching only the fields you need. For instance:
$this->db->select('u1.user_id as consignor, u2.user_id as consignee, dispatch_challan.*, challan_bilties.*, bilty.*');
give it a shot and let me know if it works
This is how to join any number of tables in codeigniter without any problems:
$this->db->select("
$table_1.id AS table_1_id,
$table_1.whatever AS table_1_whatever,
$table_2.id AS table_2_id,
$table_2.whatever AS table_2_whatever,
$table_3.id AS table_3_id,
$table_3.whatever AS table_3_whatever,
$table_4.id AS table_4_id,
$table_4.whatever AS table_4_whatever,
");
$this->db->join($table_2, "$table_2.id = $table_1.table_2_id", 'left');
$this->db->join($table_3, "$table_3.id = $table_1.table_3_id", 'left');
$this->db->join($table_4, "$table_4.id = $table_1.table_4_id", 'left');
Imagine i have a entity Person which has a many-to-many relation with Vehicle
How can i find another Person exactly having the same Vehicles?
Example:
Person 1 (ID=1) has vehicle with id 5,6 and 7
Person 2 (ID=2) has vehicles with id 5,6,8 -> should not match with person 1!
Person 3 (ID=3) has vehicle with id 5 ->should not match with person 1!
Person 4 (ID=4) has vehicles with id 5,6 and 7 -> should match with person 1
Person 5 (ID=5) has vehicles with id 5,6 and 7 -> should match with person 1 and person 4
So what is the DQL expression for that?
I tried already with "IN" but this will also match even if just one of my id's match.
Thanks
Clean DQL:
$query = $entityManager->createQuery("
SELECT p, pv
FROM Person p
INNER JOIN p.vehicles pv
WHERE pv.id in (
SELECT v.id
FROM Vehicle v
INNER JOIN v.persons vp
WHERE p.id <> vp.id
) GROUP BY p.id
HAVING count(pv.id) > 1");
$persons = $query->getResult();
Explanation:
To get persons with same vehicles, you need to get vehicles, that equal to person's, but attached to other. HAVING regulates count of minimal same vehicles, by which we group persons in collection.
You can use more flexible approach with PHP, that get only persons with full identical vehicles. Steps:
get all persons with vehicles
compare vehicles Ids
add to result only persons IDs with the same vehicles
get collection of persons with same vehicles
Code:
<?php
$query = $entityManager->createQuery("select p,v from Person p JOIN p.vehicles v");
$persons = $query->getArrayResult();
$personsIdsWithSameVehicles = [];
foreach ($persons as $person) {
$vehiclesIds = array_column($person['vehicles'], 'id');
$subPersons = array_filter($persons, function($filterPerson) use ($person) {
if($filterPerson['id'] != $person['id']) return $filterPerson;
});
foreach ($subPersons as $subPerson) {
$subVehiclesIds = array_column($subPerson['vehicles'], 'id');
if(count($vehiclesIds) == count($subVehiclesIds) and
empty(array_diff($vehiclesIds, $subVehiclesIds))) {
$personsIdsWithSameVehicles[] = $person['id'];
break;
}
}
}
$personsQuery = $entityManager->createQuery("select p from Person p where p.id IN(:persons)");
$personsQuery->setParameter('persons', $personsIdsWithSameVehicles);
$personsWithSameVehicles = $personsQuery->getResult();
I am new to laravel.
I have two tables.
1) products
2) prices
-----------------------------
- products -
-----------------------------
- id_product | int (p_key) -
- name | varchar -
-----------------------------
-------------------------
- prices -
-----------------------------
- id_price | int (p_key) -
- id_product | int -
- price | int -
-----------------------------
the products table holds data about products like id, name,...
the price changes are stored in prices table where the last record is the newest price that should be displayed to users.
now I want to search through products and get the last price of each product from prices table. this is my query:
$result = DB::table('products')->leftJoin('prices', function($join) {
$join->on('products.id_product', '=', 'prices.id_product');
})->whereRaw(MY_SEARCH_FILTERS);
the above code is wrong because if a product has 4 records in prices table, then it will be repeated 4 times in $result, but only 1 record with the last price should be displayed.
Here we have 2 tables users and answers where users is left table and answers is right table which has user answers.
We wanted to left join users with answers but the join should be with the latest record or answers table.
$query = Users::select('users.id', 'users.user_name','answers.created_at as last_activity_date')
->leftJoin('answers', function($query)
{
$query->on('users.id','=','answers.user_id')
->whereRaw('answers.id IN (select MAX(a2.id) from answers as a2 join users as u2 on u2.id = a2.user_id group by u2.id)');
})
->where('users.role_type_id', Users::STUDENT_ROLE_TYPE)->get();
you can make make it easy by using Laravel Elquent:
class Product extends Model
{
public function lastPrice()
{
// optional: change id_price to created_at by add created_at to prices table
return $this->hasOne(Price::class)->orderBy('id_price', 'DESC');
}
}
now in
public function getProducts(){
$MY_SEARCH_FILTERS=....;
// get all products with last price
$products=Product::with('lastPrice')->whereRaw(MY_SEARCH_FILTERS)->get()
return $products
}
Here we have 2 tables 'articles' and 'comments' where articles is left table and comments is right table which has article's comments.
We wanted to left join articles with comments but the join should be with the latest record from comments table.
$query = Article::select('articles.*', 'comments.comment as article_comment')
->leftJoin('comments', function($query) {
$query->on('comments.article_id','=','articles.id')
->whereRaw('comments.id IN (select MAX(a2.id) from comments as a2 join articles as u2 on u2.id = a2.article_id group by u2.id)');
})
->get();
i found this solution from here https://laravelcode.com/post/how-to-get-last-record-from-leftjoin-table-in-laravel
You need to add two things in here,
1) orderBy descending on prices table.
2) first clause in the DB::table function (It will fetch only 1
record, that will be the latest price).
The solution :
$result = DB::table('products')
->leftJoin('prices',function($join)
{
$join->on('products.id_product', '=', 'prices.id_product')
})->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();
You can also use (Laravel 5.1) :
$result = DB::table('products')
->leftJoin('products.id','=','prices.id_product')
->whereRaw(MY_SEARCH_FILTERS)
->orderBy('prices.id_price','desc')
->first();
I have a messages table.
+----+---------+----------+
| id | conv_id | body |
+----+---------+----------+
| 1 | 1 | haha |
| 2 | 1 | blabl|
| ...| ... | ... |
| 25| 2 | hehe |
+----+---------+----------+
... = rest of messages with conv_id of 2's or 1's or 3's or n's.
Let's say I have conv_id = array(2,1) and I want to obtain 10 messages after matched with an array of ids in conv_id so I did
select * from `messages` where `conv_id` in (2, 1) order by `created_at` desc limit 10
The sql above gave me 10 messages after matching both conv_ids and getting all combined messages. However, this is NOT what I wanted. Instead, I wanted 10 messages of EACH conv_id matched.
How do I get 10 messages of EACH conv_id matched? No PHP for loop, please. Thank you!
NOTE : the array conv_id can easily be extended to include many other values unique to each other, not only 2s or 1s.
P.s., bonus points for Laravel Eloquent answer! Here are the details :
Two models, Conversations and Messages linked by Conversations hasMany Message and Message belongsTo a Conversation.
My sql above was translated from Messages::with('User')->whereIn('conv_id',$conv_id)->orderBy('created_at','desc')->take(10);
I think Jared is right but if you can add another column to the table, solution would be more efficient. Add a column which indicates message number for each conv_id (earliest will have 1 and the latest will have number of messages conversation have). After that, you can achieve your goal by scanning table twice with HAVING clause.
SELECT * FROM messages JOIN
(SELECT conv_id, MAX(msg_no) FROM messages WHERE conv_id IN (2,1) GROUP BY conv_id) as M
ON messages.conv_id=M.conv_id HAVING messages.msg_no > M.msg_no-10
Another possibility. Get last conv_ids and their 10th (message)id with a group_concat - substring_index trick and re-join of message-table.
SELECT `messages`.*
FROM (
SELECT
conv_id,
substring_index(
substring_index(
group_concat(`messages`.id),
',',
10
),
',',
-1
) AS lastMessageId
FROM `messages`
WHERE `conv_id` in (2, 1)
GROUP BY `conv_id`
) AS msub
INNER JOIN `messages` ON `messages`.conv_id = msub.conv_id AND `messages`.id <= msub.lastMessageId
Warning: This approach is potentially wrong. I'm trying to validate it and will update it once I reach a conclusion
Yesterday I just learnt something new about Eloquent relationship from an answer by deczo in Getting just the latest value on a joined table with Eloquent. And I think we can adapt it to your case as well.
What you're essentially trying to do, I put in my view as:
A Conversation model that has many Messages.
But I want only 10 latest messages per each conversation. All come eager-loaded.
In Eloquent, I would probably do something along the line of:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
But two things I note of your question.
I assume you don't have another table called conversations.
The code above does not limit to how many messages per conversation.
So I decided that here should be two models, one called Message, another called Conversation.
Both call to the same table, but we will tell Eloquent to use different columns as primary key.
So to get a Conversation model, I added a distinct() to my newQuery function, and select only conv_id out since that's the only information about a conversation.
So in the end I have this:
models/Message.php
class Message extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'id';
public $timestamps = false;
}
models/Conversation.php
class Conversation extends Eloquent
{
protected $table = 'messages';
protected $primaryKey = 'conv_id';
public $timestamps = false;
public function newQuery($excludeDeleted = true)
{
return parent::newQuery()
->select('conv_id')
->distinct();
}
public function messages()
{
return $this->hasMany('Message', 'conv_id')
->orderBy('id', 'desc')
->take(10);
}
}
Now I can do:
Conversation::with('messages')->whereIn('conv_id', [1, 2])->get();
which gives me a list of conversations with conv_id 1 and 2, along with the 10 latest messages for each of them.
This is the first time I do something like this. So I code-tested and it works.
Update: The code in my answer perform these two queries only (retrieved from DB::getQueryLog()):
select distinct `conv_id` from `messages` where `conv_id` in (?, ?);
select * from `messages` where `messages`.`conv_id` in (?, ?) order by `id` desc limit 10;
I have written a model code where i am joining two tables, and returning my results.
From the below table structure my model code is showing only 2 question count, skipping the last question, After little research i found the reason why it is not counting my third question, it is because it does not have any answer in my answer table.
I want, if no answer then it should show count=0 for the particular question, How can to solve this issue?
Table structure
question
-----------
question_id PK Auto_Incr
question varchar...
votes int
answer
------------
answer_id PK Auto_icre
question_id FK refrences question
content longtext
Table Data structure data:
question
-----------
question_id question votes
1 what's name? 0
2 where you? 3
3 blah blah 9
answer
----------
answer_id question_id content
4 2 India
5 2 Nepal
6 2 Pakistan
7 1 Mr Osama Binladan
Model
public function fetch_allquestions($limit, $start)
{
$this->load->database();
$this->db->limit($limit, $start);
$this->db->from('question');
$select =array(
'question.*',
'userdetails.*',
'COUNT(answer.answer_id) AS `Answers`'
);
$this->db->select($select);
$this->db->join('answer','answer.question_id = question.question_id');
$this->db->join('userdetails','userdetails.user_id = question.user_id');
$query = $this->db->get();
print_r("Number of rows=".$query->num_rows());//showing only One, out of 26 rows
if ($query->num_rows() > 0)
{
foreach ($query->result() as $row)
{
$data[] = $row;
}
return $data;
}
else
{
return false;
}
}
You should use LEFT join
$this->db->join('answer','answer.question_id = question.question_id','LEFT');
What you need is a LEFT JOIN, which basically means that if there is a row in the table mentioned first exists, a corresponding row in the second table mentioned is not required. In your case, if there's a question, it will be returned even if there is no matching answer.
To do a left join in codeigniter, you can just pass 'left' as a third parameter to your call to join;
$this->db->join('answer','answer.question_id = question.question_id', 'left');
More info on the join call is available at the CodeIgniter docs.