Reputation: 3
Using CakePHP version 3.4.12 and MySQL... I am having trouble with the SQL and then on top of that getting the SQL into CakePHP. I want to see records that may have entered and exited today, entered today or before and may have exited today or later, or they entered today or before and still have no exit time. And skip over any records marked as inactive (inactive=true).
Excerpt of Data:
id name time_in time_out inactive
174 smith 8/15/2017 21:00 8/15/2017 21:22 NULL
175 roberts 8/15/2017 21:21 8/15/2017 21:21 NULL
176 Wagner 9/2/2017 4:40 9/3/2017 18:29 0
177 JAmes 9/1/2017 3:35 NULL 0
178 john 9/4/2017 3:59 9/4/2017 22:22 NULL
180 erwer 9/4/2017 4:01 NULL 1
181 waynbe 9/4/2017 4:02 NULL NULL
182 Roger 9/4/2017 22:21 9/4/2017 22:22 NULL
183 Felix 9/4/2017 22:24 NULL NULL
In Case I have made a mistake in the SQL, I want to find all records that are
NOT 'inactive' (not TRUE)
also where
'time_in' <= '2017-09-04 23:59:59' AND 'time_out' >= '2017-09-04 00:00:00'
---- OR ----
'time_out' is NULL AND 'time_in' <= '2017-09-04 23:59:59'
Desired returned results are:
id name time_in time_out inactive
177 JAmes 9/1/2017 3:35 NULL 0
178 john 9/4/2017 3:59 9/4/2017 22:22 NULL
181 waynbe 9/4/2017 4:02 NULL NULL
182 Roger 9/4/2017 22:21 9/4/2017 22:22 NULL
183 Felix 9/4/2017 22:24 NULL NULL
The conditional SQL I am attempting to achieve is:
WHERE (time_in <= '2017-09-04 23:59:59' AND time_out >= '2017-09-04 00:00:00')
OR (isnull(time_out) AND time_in <= '2017-09-04 23:59:59')
AND inactive != 1
This gives the results and is missing data:
id name time_in time_out inactive
177 JAmes 9/1/2017 3:35 NULL 0
178 john 9/4/2017 3:59 9/4/2017 22:22 NULL
182 Roger 9/4/2017 22:21 9/4/2017 22:22 NULL
However, when attempting in CakePHP using:
$query= $this->StationEntries->find('all')
->andWhere(['time_in <='=> $dateIn, 'time_out >='=>$dateOut])
->orWhere(['isnull(time_out)', 'time_in <='=> $dateIn])
->andWhere(['inactive !='=>true]);
Creates the SQL:
WHERE
(
(
(
time_in <= '2017-09-04 23:59:59'
AND time_out >= '2017-09-04 00:00:00'
)
OR (
isnull(time_out)
AND time_in <= '2017-09-04 23:59:59'
)
)
AND inactive != 1
)
This is returning the following results and is missing even more records.
id name time_in time_out inactive
177 JAmes 9/1/2017 3:35 NULL 0
The following does work correctly except it doesn't filter out the inactive records.
$query= $this->StationEntries->find('all')
->where(['time_in <='=> $dateIn, 'time_out >='=>$dateOut])
->orWhere(['isnull(time_out)', 'time_in <='=> $dateIn]);
I have read in the book:
As of 3.5.0 the orWhere() method is deprecated. This method creates hard to predict SQL based on the current query state. Use where() instead as it has more predicatable and easier to understand behavior.1
So I am asking for help in two areas:
Thank you for your help.
Upvotes: 0
Views: 154
Reputation: 3
First off, IS NULL is not equivalent to !TRUE ( != 1 ). That was the first problem. Fixed.
Correct SQL came from (Thanks to @cwallenpoole for a push in the right direction) a simplifed query from the original:
->where( [ 'time_in <=' => $dateIn, 'inactive IS NULL',
'OR' =>(['time_out >=' => $dateOut,'time_out IS NULL' ])])
If you remove nulls from your schema then it would look like:
->where( [ 'time_in <=' => $dateIn, 'inactive !=' =>1,
'OR' =>(['time_out >=' => $dateOut,'time_out IS NULL' ])])
This results in CakePHP query of:
WHERE
(
time_in <= '2017-09-04 23:59:59'
AND inactive IS NULL
AND (
time_out >= '2017-09-04 00:00:00'
OR time_out IS NULL
)
)
And this returns the correct Rows.
Upvotes: 0
Reputation: 81988
Per docs, to add an 'OR' clause, you need to have the 'OR' be the key in the array. I think you're looking for:
->where(
[
'time_in <=' => $dateIn, 'time_out >=' => $dateOut,
'OR' => [
['time_out IS NULL', 'time_in <=' => $dateIn
]
]
)->andWhere( [ 'inactive !=' => 1 ] )
Basically, that should result in:
(
(time_in < dateIn AND time_out < dateOut)
OR ( time_out IS NULL AND time_in < dateIn)
)
AND ( inactive != 1 )
You could simplify to:
->where( [ 'time_in <=' => $dateIn ], [ 'inactive !=' => 1 ] )
->andWhere(
[
'time_out >=' => $dateOut,
'OR' => [ 'time_out IS NULL' ]
])
Upvotes: 1