Get data from 2 tables with a join - php

I have these 2 tables : keyword and keyword_translated
keyword
id
name
keyword_translated
id
translation
keyword_id
I want to get all keyword, doesn't matter has or not relation with keyword_translated. At the end I want to get something like :
[
[
keyword_id => 1,
keyword_name => 'firstKeyword'
keyword_translated_id => 1, // if exist relation between `keyword` and `keyword_translated`
keyword_translated_translation => 'This is translation of firstKeyword' // if exist relation between `keyword` and `keyword_translated`
],
[
keyword_id => 2,
keyword_name => 'secondKeyword'
keyword_translated_id => null, // if didn't exist relation between `keyword` and `keyword_translated`
keyword_translated_translation => null // if didn't exist relation between `keyword` and `keyword_translated`
],
]
I tried like this :
$keywords = DB::table('keywords')
->join('keywords_translated', 'keywords.id', '=', 'keywords_translated.keyword_id')
->select('keywords.*', 'keywords_translated.*')
->get();
But I have empty data. What can I try to resolve this?

use leftjoin instead of join like this:
$keywords = DB::table('keywords')
->leftjoin('keywords_translated', 'keywords.id', '=','keywords_translated.keyword_id')
->select(
'keywords.id as keyword_id',
'keywords.name as keyword_name',
'keyword_translated.id as keyword_translated_id',
'keyword_translated.translation as keyword_translated_translation',
)
->get();

Save this image for future reference.

Related

Get all rows where the field is not NULL in CakePHP 3

How can I get all the instances of a Table where the fields are not NULL ?
Here is the configuration:
I have a Table 1 where the instances have a relationship "hasmany" with a Table 2. I want to get all the instances of Table 1 linked with a Table 2 instance not NULL.
The CakePHP doc helped me finding the exists() and isNotNull() conditions but I did not achieve.
Here is how I imagined:
$Table1 = TableRegistry::get('Table1')->find('all')->contain([
'Table2' => [
'sort' => ['Table2.created' => 'desc']
]
])->where([
'Table1.id' => $id,
'Table2 IS NOT NULL'
]);
$this->set(compact('Table1'));
But it obviously does not work.
edit : I expect to get all the line of the Table1 which contain existing Not NULL Table2 line(s) linked. The problem is in the 'where' array with the 'Table2 IS NOT NULL', it does not work.
And without this line 'Table2 IS NOT NULL', I get all the Table1 line which contain a Table2 line or not (because some line of Table1 are not linked at all and I don't want to get these lines).
Assuming the tables follow convention and use "id" as the primary key, I suggest the easiest fix would be testing that field for NOT NULL.
I.e., replace this:
'Table2 IS NOT NULL'
with this:
'Table2.id IS NOT NULL'
or:
'Table2.id !=' => null
or:
'Table2.id >' => 0
I've successfuly get the Table1 lines with its existing Table2 line(s) associated.
query = TableRegistry::get('Table1')->find();
$query->select(['Table1.id', 'count' => $query->func()->count('Table2.id')])->matching('Table2')->group(['Table1.id'])->having(['count
>' => 0]);
$table1Ids = [];
foreach ($query as $z)
{
$table1Ids[] = $z->id;
}
$table1= TableRegistry::get('Table1')->find('all')->contain([
'Table2' => [
'sort' => ['Table2.created' => 'desc']
]
])->where([
'id IN' => $table1Ids,
]);

Sql query to cakephp query using associations

Here is my correct sql query:
SELECT * FROM `messages` WHERE ( (sender_id=3 AND user_id=40) OR (sender_id=40 AND user_id=3)) AND offer_id=1
I want to use this in Cakephp syntax:
$this->Message->find('all',array('conditions'=>array(
'AND'=>array(
'OR'=>array(
'Message.offer_id'=>$offer_id,
'Message.sender_id'=>$sender_id,
'Message.user_id'=>$this->Auth->user('id'),
),
'OR'=>array(
'Message.offer_id'=>$offer_id,
'Message.user_id'=>$sender_id,
'Message.sender_id'=>$this->Auth->user('id')
)
)
),
'recursive'=>2
));
Is there anyone who can help me to figure out the issue. Basically I want to get all the messages whether I sent or received for an particular offer.
You should move $offer_id out of or conditions and move it to and conditions.
Why? Lets look at your first or array:
That conditions will return true if:
sender_id is 3
OR user_id is 40
OR offer_id is 1
So, that condition may return true event if offer_id != 1
That should be written this way (as precisely as possible according to original query):
$query = $this
->Messages
->find('all' , [
'conditions' => [
'or' => [
[
'sender_id' => $sender_id,
'user_id' => $this->Auth->user('id')
], [
'sender_id' => $this->Auth->user('id'),
'user_id' => $sender_id
]
],
'offer_id' => $offer_id,
]
]);
dump($query);
In dump we can see something like this:
"SELECT * FROM messages Messages WHERE (((sender_id = :c0 AND user_id = :c1) OR (sender_id = :c2 AND user_id = :c3)) AND offer_id = :c4)
asterisk in sql query dump for more readability
You have the AND and OR operators reversed.
'OR'=>array(
'AND'=>array(
'Message.offer_id'=>$offer_id,
'Message.sender_id'=>$sender_id,
'Message.user_id'=>$this->Auth->user('id'),
),
'AND'=>array(
'Message.offer_id'=>$offer_id,
'Message.user_id'=>$sender_id,
'Message.sender_id'=>$this->Auth->user('id')
)
)

GroupBy Query Laravel 5.1

I'm having problem in fetching the data using groupBy, I don't where I'm wrong, I have done it many times before, but today I'm wrong some where and I don't know where. Following is the Table from which I want to select the Data:
Table Name: user_questions
id | user_id | message | read_status_user | read_status_support | answered
Now suppose if one user sends more than one messages, then user_id will be repeated, So to want all the message from one particular user I'm firing the query like following:
UserQuestion::groupBy('user_id')->get();
This should give me the result like
user_id = 1 > message1
user_id = 1 > message2
....
user_id = 1 > message...(if any)
user_id = 2 > message1
user_id = 2 > message2
.....
So on...
But this is always giving me only one message from the particular user. I don't know why. Is there any mistake? I have tried another queries too, but all are giving me the same result.
Please help me with this. Everybody's help will be highly appreciated. Thanks to all of you in advance.
The issue here is that you are calling the groupBy function of the query builder object, which is what generates the query for your database. When you call the ->get() method, the query is executed and a Collection object containing the results is returned. What you are looking to use is the groupBy method of Laravel's Collection class, which means you need to put the ->groupBy('user_id') after the ->get().
Assuming you have the following data:
user_question
user_id question_id
1 1
1 2
1 3
2 4
3 5
3 6
Your current code
UserQuestion::groupBy('user_id')->get();
executes this query
select * from user_question group by user_id;
returning one row per user, since that's what group by does in MySQL.
user_id question_id
1 1
2 4
3 5
If instead, you do the following
$collection = UserQuestion::get();
the query is simply
select * from user_question
and when you call $collection->groupBy('user_id') on this collection, you get data structured like
[
1 => [
[ 'user_id' => 1, 'question_id' => 1 ],
[ 'user_id' => 1, 'question_id' => 2 ],
[ 'user_id' => 1, 'question_id' => 3 ]
],
2 => [
[ 'user_id' => 2, 'question_id' => 4 ],
],
3 => [
[ 'user_id' => 3, 'question_id' => 5 ],
[ 'user_id' => 3, 'question_id' => 6 ]
]
]
Try like this
$users = DB::table('table_name')
->groupBy('user_id')
->get();
after that push that to foreach loop
foreach ($users as $user)
{
var_dump($user->name);
}
ordering-grouping-limit-and-offset in Laravel
You've probably found the solution to your problem by now but otherwise, I would suggest to use the relationships. In the User model, I would do:
public function questions()
{
return $this->hasMany('App\UserQuestion');
}
Then I would get all the users and loop through them to get their messages.
$users = User::all();
$users->each(function ($user) {
$questions = User::find($user->id)->questions;
});

SQL to ActiveRecord criteria

I am trying to reproduce the following SQL in an ActiveRecord Criteria:
SELECT COALESCE(price, standardprice) AS price
FROM table1
LEFT JOIN table2
ON (pkTable1= fkTable1)
WHERE pkTable1= 1
So far I have the following:
$price = Table1::model()->find(array(
"select" => "COALESCE(price, standardprice) AS price",
'with' => array(
'table2' => array(
'joinType' => 'LEFT JOIN',
'on' => 'pkTable1= fkTable1',
)
),
'condition' => 'pkTable1=:item_id',
'params' => array(':item_id' => 1)
));
But this results into the following error: 'Active record "Table1" is trying to select an invalid column "COALESCE(price". Note, the column must exist in the table or be an expression with alias.
The column should exist though, here are the 2 table structures:
Table1
pkTable1 int(11) - Primary key
standardprice decimal(11,2)
name varchar(255) //not important here
category varchar(255) //not important here
Table2
pkTable2 int(11) - Primary key //not important here
fkType int(11) - Foreign key //not important here
fkTable1 int(11) - Foreign key, linking to Table1
price decimal(11,2)
What exactly am I doing wrong?
You will need to use a CDbExpression for the COALESCE() expression:
$price=Table1::model()->find(array(
'select'=>array(
new CDbExpression('COALESCE(price, standardprice) AS price'),
),
'with' => array(
'table2' => array(
'joinType'=>'LEFT JOIN',
'on'=>'pkTable1=fkTable1',
),
),
'condition'=>'pkTable1=:item_id',
'params'=>array(':item_id'=>1)
));
I further believe if table2 has been linked in the relations() method in your Table1 model, the following line should be sufficient:
'with'=>array('table2'),
I've managed to solve the issue as following: Wrap the COALESCE expression in an array, and change the alias to an existing columnname in the table.
$price = Table1::model()->find(array(
"select" => array("COALESCE(price, standardprice) AS standardprice"),
'with' => array(
'table2' => array(
'joinType' => 'LEFT JOIN',
'on' => 'pkTable1= fkTable1',
)
),
'condition' => 'pkTable1=:item_id',
'params' => array(':item_id' => 1)
));
Thank you to Willemn Renzema for helping me with the array part. I'm still not entirely sure why the alias needs to be an existing column name (in this case the error was that price doesn't exist in Table1).

Getting the column 'country_id' in 'where' clause is ambiguous - error in search query in cakephp 1.3

I am working with CakePHP 1.3 version for search functionality using Search Plugin.
I have three models:
Demo,
Country
State
Demo has two foreign keys, country_id and state_id. State has the foreign key country_id.
What I am doing is, I have search form which have country & state drop down which fetch all data from countries & states table. When i search any of country from dropdown & submit the form it will show me below error. If i search using only state dropdown i get the correct result.
When I execute the search query, I get the error
'Column 'country_id' in where clause is ambiguous'
My query is:
SELECT `Demo`.`id`, `Demo`.`demo2`, `Demo`.`desc`, `Demo`.`subject`, `Demo`.`gender`, `Demo`.`country_id`, `Demo`.`state_id`, `Demo`.`image_url`, `Country`.`id`, `Country`.`name`, `State`.`id`, `State`.`country_id`, `State`.`description` FROM `demos` AS `Demo` LEFT JOIN `countries` AS `Country` ON (`Demo`.`country_id` = `Country`.`id`) LEFT JOIN `states` AS `State` ON (`Demo`.`state_id` = `State`.`id`) WHERE `country_id` = 2
Model relationships in Demo table:
var $belongsTo = array(
'Country' => array(
'className' => 'Country',
'foreignKey' => 'country_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'State' => array(
'className' => 'State',
'foreignKey' => 'state_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
);
The controller query to fetch all Country in dropdown is:
$country=$this->Country->find('list'); //just display the list of country in dropdown
The query search the data from all fields except Country (country_id), because it will not know which country_id it is looking for from table Demo or table State. I need the country_id from the demo table to get the correct result.
As I understand you want to make a find over Demo for a specific country_id.
Well you should define which "country_id" you're using because more than one of those tables
has such a column.
Just use Demo.country_id in the conditions array:
array('conditions' => array('Demo.country_id' => 2));
And you should see some SQL generated by Cake like this:
SELECT `Demo`.`id`, `Demo`.`demo2`, `Demo`.`desc`, `Demo`.`subject`, `Demo`.`gender`, `Demo`.`country_id`, `Demo`.`state_id`, `Demo`.`image_url`, `Country`.`id`, `Country`.`name`, `State`.`id`, `State`.`country_id`, `State`.`description` FROM `demos` AS `Demo` LEFT JOIN `countries` AS `Country` ON (`Demo`.`country_id` = `Country`.`id`) LEFT JOIN `states` AS `State` ON (`Demo`.`state_id` = `State`.`id`) WHERE `Demo`.`country_id` = 2
Try this:
SELECT
Demo.id,
Demo.demo2,
Demo.desc,
Demo.subject,
Demo.gender,
Demo.country_id,
Demo.state_id,
Demo.image_url,
Country.id,
Country.name,
State.id,
State.country_id,
State.description
FROM demos AS Demo
LEFT JOIN countries AS Country ON (Demo.country_id = Country.id)
LEFT JOIN states AS State ON (Demo.state_id = State.id) WHERE Demo.country_id = 2

Categories