CakePHP find with 'AND', 'OR' and 'NOW()::date' - cakephp

I'm trying to translate this query in a find, but without success. My find doesnt return anything.
My SQL (in postgresql)
select * from projectversion where project='10003' releasedate>=now()::date or releasedate is null
MY FIND
$projectversions = $this->find('list', array(
'recursive' => -1,
'fields' => array('vname'),
'conditions' => array('project' => $id_project,'releasedate >=now()::date','OR'=>array('releasedate is null'))));
Anyone can help me?

Your original SELECT doesn't appear to be valid:
select * from projectversion where project='10003' releasedate>=now()::date or releasedate is null
Should it be:
select * from projectversion where project='10003' AND (releasedate>=now()::date or releasedate is null)
If so, your conditions should look like:
'conditions'=>array(
'Model.project'=>10003,
OR=>array(
'Model.releasedate >= NOW()'
'Model.releasedate IS NULL'
)
)
produces:
WHERE Model.project = 10003 AND (Model.releasedate >= NOW() OR Model.releasedate IS NULL)

Related

Cake php multiply Find Conditions OR /AND

hey guys i have been struggling with this .i am a trying to select from a table using cakephp find all e.g
i want to select all from a table where (A == 1 AND B == 2) OR (A == 2 and B == 1) with just on query
here is my code so far
$conditions = array("OR"=>
array("Message.to_to"=>$daddy["User"]["id"],
"Message.from_from"=>$this->Auth->user("id")),
array("Message.to_to"=>$this->Auth->user("id"),
"Message.from_from"=>$daddy["User"]["id"])
);
To get your expected result (A == 1 AND B == 2) OR (A == 2 and B == 1), try nesting the 'and' conditions which are currently missing from your code.
You also need to specify the conditions parameter.
Try the following:
$conditions = array(
'conditions' => array(
"or"=> array(
"and" => array(
"Message.to_to"=>$daddy["User"]["id"],
"Message.from_from"=>$this->Auth->user("id"),
),
"and" => array(
"Message.to_to"=>$this->Auth->user("id"),
"Message.from_from"=>$daddy["User"]["id"],
),
),
),
);
Reference: http://book.cakephp.org/2.0/en/models/retrieving-your-data.html

cakephp: find ignores DISTINCT

i got the following cakephp find situation:
$data = $this->find('all', array(
'conditions' => array(
'Roster.league_id' => $league_id,
'Roster.season' => $season,
),
'fields' => array(
'DISTINCT Roster.player_id',
'Roster.league_id',
'Roster.fflteam_id',
'Roster.season',
'Roster.modified',
'Fflteam.name',
'Player.firstName',
'Player.lastName',
'Player.position'
),
'order' => array(
'Roster.player_id',
'Roster.modified DESC'),
'contain' => array(
'Fflteam',
'Player' => array(
'Stat' => array(
'conditions' => array(
'Stat.season' => $season),
'Scores'),
'Teamplayer')
)
));
There are more Roster-records with specific player_ids, thats why i try to use DISTINCT. I only need the most recent. Thats why i order the results by player_id and Roster.modified. But die DISTINCT command gets ignored.
e.g:
records:
id=1 player_id=1 modified=2012
id=2 player_id=1 modified=2013
id=3 player_id=1 modified=2014
id=4 player_id=2 modified=2014
id=5 player_id=2 modified=2013
result should be:
id=3 player_id=1 modified=2014
id=4 player_id=2 modified=2014
I don't see any syntax errors. Maybe there some commands are not possible together or my way of filtering is wrong. would be great if someone can help me.
DISTINCT does not give you one distinct field if there are multiple fields , if you have Distinct title it will provides distinct title .
If you have distinct id , title it will output distinct combination of rows with same id and title.
This is how DISTINCT works.
Try GroupBy
Check this page to understand what to use when http://www.mysqltutorial.org/mysql-distinct.aspx
As AgRizzo suggested i am using a query now.
Its split into 2 Parts. The first gets all entries with the one2one relations:
$this->query("SELECT *
FROM (SELECT * FROM `rosters` AS `Roster1` WHERE " . $conditions . " ORDER BY `Roster1`.`modified` DESC) AS `Roster`
LEFT JOIN `fflteams` AS `Fflteam` ON (`Roster`.`fflteam_id` = `Fflteam`.`id`)
LEFT JOIN `players` AS `Player` ON (`Roster`.`player_id` = `Player`.`id`)
GROUP BY `Player`.`id` ORDER BY `Roster`.`player_id` ASC");
The second part gets all one2many relations with its relation:
$this->Stat->find('all', array(
'conditions' => $conditions,
'contain' => array(
'Scores')
));
at the end i merge those 2 arrays

CakePHP find joined records with conditions on each table

I want to see all the records from a join, setting a WHERE condition on each side of the join.
For example, I have LOAN and BORROWER (joined on borrower.id = loan.borrower_id). I want the records where LOAN.field = 123 and BORROWER.field = 'abc'.
The answers here (this one, for example) seem to say that I should use Containable.
I tried that. Here's my code:
$stuff = $this->Borrower->find('all', array(
'conditions' => array(
'Borrower.email LIKE' => $this->request->data['email'] // 'abc'
),
'contain'=>array(
'Loan' => array(
'conditions' => array('Loan.id' => $this->request->data['loanNumber']) // 123
)
)
));
I expected to have a single result because in my data, there is only one joined record with both of those conditions. Instead, I get two results,
Result 1 is {Borrower: {field:abc, LOAN: {field: 123} } // correct
Result 2 is {Borrower: {field:abc, LOAN: {NULL} } // incorrect
When I look at the SQL that CakePHP used, I don't see a join. What I see is two separate queries:
Query 1: SELECT * from BORROWER // (yielding 2 IDs),
Query 2: SELECT * FROM LOAN WHERE borrower_id in (IDs)
This is not what I want. I want to join the tables, then apply my conditions. I could easily write the SQL query, but am trying to do it the Cake way since we've adopted that framework.
Is it possible?
Try to do something like this:
$options['conditions'] = array(
'Borrower.email LIKE' => $this->request->data['email'] // 'abc',
'loan.field' => '123' )
$options['joins'] = array(
array('table' => 'loans',
'alias' => 'loan',
'type' => 'INNER',
'conditions' => array(
'borrower.id = loan.borrower_id')
)
);
$options['fields'] = array('borrower.email', 'loan.field');
$test = $this->Borrower->find('all', $options);
You should see a SQL statement like:
SELECT borrower.email, loan.field
FROM borrowers AS borrower
INNER JOIN loans AS loan
ON borrower.id = loan.borrower_id
AND loan.field = '123'
WHERE borrower.email = 'abc'
Your results will be in an array
{Borrower: {field:abc} LOAN: {field: 123} }
You will find more information in this document.
I think I'll accept Jose's answer because it's exactly what I want. But I did notice that I didn't need any fancy tricks -- no joins or contains -- if I used the other model as my starting point.
A Borrower hasMany Loans, and a Loan belongsTo a Borrower. Using Loan as my model, Cake will automatically join the tables, but not using Borrower.
$this->Loan->find('all', array( // Not $this->Borrower->find() !
'conditions' => array(
'Borrower.field' => 'abc',
'Loan.field' => 123
)
));

Cake PHP complex find 'OR' is not working properly with null and empty string

Cake PHP complex find 'OR' opertor is not working properly with null...
$conditions = array(
'Person.id' => array(2, 4, 1, 23, 45, 11),
'OR' => array(
array(
array('NOT' => array('Person.image' => null)),
array('NOT' => array('Person.image' => '')),
),
array(
array('NOT' => array('Person.photos' => null)),
array('NOT' => array('Person.photos' => '')),
)
)
);
The corresponding cake sql dump output query as below
SELECT `Person`.`id`, `Person`.`created`, `Person`.`modified`
FROM `people` AS `Person` WHERE `Person`.`id` IN (2, 4, 1, 23, 45, 11) AND
((((NOT (`Person`.`image` IS NULL)) AND (NOT (`Person`.`image` = NULL)))) OR
(((NOT (`Person`.`photos` IS NULL)) AND (NOT (`Person`.`photos` = '')))))
ORDER BY FIELD(`Person`.`id`, 2, 4, 1, 23, 45, 11) ASC LIMIT 3
In cake condition array, I have given Person.image is not null or '', but corresponding cake sql outputs as (NOT (Person.image IS NULL)) AND (NOT (Person.image = NULL)) where it should be like (NOT (Person.image IS NULL)) AND (NOT (Person.image = '')) .
Here Person.image both are compared with NULL itself(IS NULL and = NULL), where Person.image = NULL want to compared with empty string like Person.image = ''.
Here 'Person.image' is 'INT' and 'Person.photos' is 'VARCHAR' of type, but it is difficult to change type from current stage.
How it can be corrected ?
You are not forced to use an associative array to define conditions. You can define it like so:
$conditions = array(
'Person.id' => array(2, 4, 1, 23, 45, 11),
'OR' => array(
array(
array('NOT' => array('Person.image' => null)),
array('NOT' => array('Person.image = "" ')),
),
array(
array('NOT' => array('Person.photos' => null)),
array('NOT' => array('Person.photos = "" ')),
)
)
);
Perhaps there is an issue with interpreting 'Person.image <>' => null, since it is not strictly valid SQL (at least not in MySQL).
From the MySQL manual:
You cannot use arithmetic comparison operators such as =, <, or <> to test for NULL.
You could try replacing it with a negated null comparison:
array('NOT' => array('Person.image' => null))
Aside from that, your last two OR operators does nothing, since you only have one statement in each. Is your array nesting what you ment it to be? If you add newlines and indentation, your code becomes
$conditions = array(
'Person.id' => array(2, 4, 1, 23, 45, 11),
'OR' => array(
array(
'OR' => array(
'Person.image <>' => null
),
array(
'Person.image <>' => ''
)
),
array(
'OR' => array(
'Person.photos <>' => ''
),
array(
'Person.photos <>' => null
)
)
)
);
...which looks weird.
The full change would be:
$conditions = array(
'Person.id' => array(2, 4, 1, 23, 45, 11),
'OR' => array(
array(
array('NOT' => array('Person.image' => null)),
array('NOT' => array('Person.image' => '')),
),
array(
array('NOT' => array('Person.photos' => null)),
array('NOT' => array('Person.photos' => '')),
)
)
);
It appears that Cake's null comparison depends on the database field type. If your field is of type integer then Cake will redefine '' as Null. Varchars will not be redefined.
Are you able to go to MySQL and change the Person.image type to varchar?
If so remember to clear your cache in app/tmp/cache/models for Cake to register changes.
UPDATE: manually changing the schema type will force cake to treat a field type as defined. So something like this prior to the query will work:
$this->Person->_schema['image']['type']='string';
Sorry, those answers are in my opinion not 100% right, they provide workarounds but no solution.
The problem are the database column types:
Person.image is INT and Person.photos is VARCHAR of type
Well, '' (the empty string) is not a valid value for an integer, ever. I assume you have allowed NULL values on the Person.image column, so cake does the right job!
It just doesn't make any sense to ask if an integer field has the value of the empty string, it can only be NULL, 0, 1, -1, 2, -2, etc. (if signed).
What happens here is that cake knows about your data structure (note the DESCRIBE queries when the debug flag is > 0), so it tries to correct your statement to the next useful one - testing for NULL values. Moreover, even if you ask MySQL (or force cake doing so) to query your DB, there will never be any effect because of this condition (maybe because of the other ones):
SELECT * FROM table WHERE my_int_column = '' is completely legit SQL but will always return 0 results whereas SELECT * FROM table WHERE NOT(my_int_column = '') will always return all results.
Conclusion: if your app works by now with the ='' condition, it will work exactly the same without the condition.
Final note: However, you can INSERT the empty string into an integer column and it will be converted by MySQL to 0, so you might want to check for those.

convert query() to find() cakephp

$v = array(1,11.38,15.8);
$sortByPrice = $this->Product->query
(
"SELECT *,
CASE `currency`
WHEN '1' THEN $v[0]
WHEN '2' THEN $v[1]
WHEN '3' THEN $v[2]
END AS 'ratio'
FROM products
ORDER BY price*ratio DESC
"
);
i want to convert what is above to a find function
i tried something like that(but it do not work)..
$v = array(1,11.38,15.8);
$bla = $this->Product->find('all', array(
'conditions' => array(
'Product.currency',
'((
CASE WHEN
Product.currency=1 THEN $v[0]
Product.currency=2 THEN $v[1]
Product.currency=3 THEN $v[2]
END
)) AS ratio'),
'order' => 'ratio',
'limit' => 10
));
can somebody to convert query into find
You are putting into the conditions key. Move it into the fields key or make it a virtualField - that may work.
Edit: also $v[0] in single quotes will not actually replace it with the variable - it will just appear as that text.

Resources