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,
]);
Related
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.
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')
)
)
I'm currently using doctrine dbal for my database queries. I'm also using the querybuilder. And I was wondering how I could select two tables and get the results in an array that has prefixed keynames for one of the tables joined.
Here is an example of the desired result:
$data = [
key1 => 'value1',
key2 => 'value2',
key3 => 'value3',
key4 => 'value4',
table2.key1 => 'value1',
table2.key2 => 'value2',
table2.key3 => 'value3',
]
Thanks
I have just faced with the same problem and I resolved it in next way:
$result = $this->createQueryBuilder('comments')
->select([
'comments.id as id',
'comments.post_id as postId',
'comments.userId as userId',
'comments.userName as userName',
'comments.userEmail as userEmail',
'comments.parentId as parentId',
'comments.postedAt as postedAt',
'comments.status as status',
'comments.comment as comment',
'user.fullname as user_userName',
'user.email as user_email',
])
->leftJoin(
'Entity\User', 'user',
Query\Expr\Join::WITH,
'comments.userId = user.id'
)
->where('comments.post_id=:postId')->setParameter('postId', $postId)
->getQuery()
->getResult(Query::HYDRATE_ARRAY)
;
So, to add prefixes to table data, just declare them into "select" statement as
table.var1 as prefix_var1, table.var2 as prefix_var2
and the result will be
[
prefix_var1 => value,
prefix_var2 => value,
]
one more thing that you can do, when you declare select as:
table1, table2.var1 as prefix_var1, table2.var2 as prefix_var2
you will get the next result
[
0 => [ // it's come from table1
var1 => value,
var2 => value,
],
prefix_var1 => value, // it's come from table2
prefix_var2 => value, // it's come from table2
]
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).
Please help me to retrieve data from a table by multiple condition in Cakephp
I have one table name: article; I have tried to retrieve data with the code below
I want to get specific id as given in the parameter; article_price > 0 and article_status > 1
public function getArticle($artID = ''){
return $this->find('all', array(
'condition' => array(
'article_id =' => $artID,
'article_price' => '> 0',
'article_status = ' => '1'),
'order' => 'article_id DESC'
));
}
// the out put was selected all data without condition that I want.
What was the problem with my code?
What I found out is I print: echo $this->element ('sql_dump'); and I got the following sql statement:
SELECT `article`.`article_id`, `article`.`name`, `article`.`article_price`, `article`.`article_status` FROM `db_1stcakephp`.`article` AS `article` WHERE 1 = 1 ORDER BY `article_id` DESC
Please help me.
Thank!
If your model name is Article:
public function getArticle($art_id) {
return $this->find('first', array(
'conditions' => array(
'Article.article_id' => $art_id,
'Article.article_price >' => 0,
'Article.article_status >' => 1,
),
));
}
Using 'Model.field' syntax is optional, until your models have relationship and have the same names - for example Article.status and Author.status.
Moving comparison sign into array's key part allows you to do:
'Article.price >' => $minPrice,
'Article.price <=' => $maxPrice,
And I didn't really notice typo in 'conditions'.