简体   繁体   中英

CakePHP Multi-Conditional SQL statement

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:

  1. Where is my mistake in the SQL WHERE clause and what should it be?
  2. How to translate that into CakePHP Query builder and how to do it while avoiding the orWhere() method?

Thank you for your help.

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' ]
])

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM