How can I emulate WHERE 1 in a dynamic query?

2019-07-23 05:41发布

I'm making a query dynamically like this:

$query = "SELECT u.*
          FROM users u
          WHERE date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 $range))";

Also $range contains a word like this:

switch ($_GET['range']){
   case "week":
      $range = "WEEK";
   case "month":
      $range = "MONTH";
   case "year":
      $range = "YEAR";
   case "ALL":
      $range = <I don't know what should I put here to get the expected result>;
}

As I've said above, I want to set something as $range value to make the WHERE clause something like WHERE 1. How can I do that?

5条回答
女痞
2楼-- · 2019-07-23 05:56

I would define an array with valid ranges and validate the user input first. Then build the query dynamicly.

$validRanges = [
    'year'  => 'YEAR',
    'month' => 'MONTH',
    'week'  => 'WEEK',
    'ALL'   => null
];

if (isset($_GET['range']) && !isset($validRanges[$_GET['range']])) {
    $range = $validRanges[$_GET['range']]);
} else {
    // it's up to you, what to do in this case
    throw new Exception('Range is not valid or missing');
}

if ($range === null) {
    $rangeCondition = '1=1';
} else {
    $rangeCondition = "date_time > unix_timestamp(NOW() - INTERVAL 1 $range)";
}

$query = "SELECT u.*
          FROM users u
          WHERE $rangeCondition";
查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-07-23 06:00
switch ($_GET['range']){
  case "week":
  $range = "WEEK";
 case "month":
  $range = "MONTH";
 case "year":
  $range = "YEAR";
 case "ALL":
  $range = null;
}

$query = "SELECT u.*
      FROM users u
      WHERE 1=1 ";
if(!empty($range)) {
  $query .= " AND date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 $range))";
}

Add datetime where clause conditionally; WHERE 1=1 will always be true. So the next condition's result will matter on the final result

查看更多
做自己的国王
4楼-- · 2019-07-23 06:03

Let's start with the fact that your switch statement doesn't have break statements and isn't going to work the way you expect.

Here is what I'd suggest:

$query = "SELECT u.*
          FROM users u";

$range = false;

if (isset($_GET['range'])) {    
    switch ($_GET['range']){
       case "week":
          $range = "WEEK";
          break;
       case "month":
          $range = "MONTH";
          break;
       case "year":
          $range = "YEAR";
          break;
       default:
          $range = false;
    }
} 


if ($range) {
  $query .= " WHERE date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 $range))";
}
查看更多
仙女界的扛把子
5楼-- · 2019-07-23 06:13

I think what Adam was suggesting is something like this:

$where = '';

switch ($_GET['range']) {

    case "week":
       $where = "date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 WEEK))":
        break;

    case "month":
       $where = "date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 MONTH))":
        break;

    case "year":
       $where = "date_time > unix_timestamp(DATE_SUB(now(), INTERVAL 1 YEAR))":
        break;

    default:
        $where = '';
}

$query = "SELECT u.* FROM users u WHERE $where";

Assume reporting with other criteria? Where the string concatenation gets messy. Adding 'AND' between parts. Suppressing WHERE keyword entirely? Where OOP code to represent the SQL query can be useful.

查看更多
地球回转人心会变
6楼-- · 2019-07-23 06:21

Perhaps use a case statement in your where clause?

 $query = "SELECT u.*
           FROM users u
           WHERE CASE {$range}
                 WHEN 'ALL' then TRUE
                 ELSE date_time > unix_timestamp(DATE_SUB(now()
                                  , INTERVAL 1 {$range}))
                 END";
查看更多
登录 后发表回答