Laravel雄辩地说,当行满足2个条件时,如何从查询中排除行?

时间:2019-03-21 19:28:17

标签: php laravel eloquent

所以我试图创建一个Laravel雄辩的查询。它有点复杂,有很多子句,所有子句都运行良好,并且正在查询单个表。但是,我想添加一个特定条件,如下所述。

->where('date', '>', Carbon::now())

此条件工作正常,但我希望此条件仅适用于特定行!假设我希望上述where子句适用的条件是:

->where('row_type', '=', 'someType')

现在,我不想过滤row_type ='someType'的所有行,也不过滤date> Carbon :: now()的所有行。

当row_type ='someType'时,我只想过滤日期> Carbon :: now()的行。

当然,“ date”和“ row_type”都是我表中的列。

现在,为了简化逻辑,我想做的基本上是排除两个都正确的行(日期

是否可以在雄辩的单个查询中完成而无需插入原始sql?

我能够在原始sql中重现我的查询:

select id, date, row_type from my_table where case when row_type = 'someType' then date > '2019-03-01%' end;

1 个答案:

答案 0 :(得分:1)

  

现在,为了简化逻辑,我想做的基本上是排除两个都正确的行(日期

要么应用形式布尔逻辑!(A and B) = !A or !B,要么只是注意到“排除其中都为真的”等同于“包括如果任何一个为假的则包括”。因此,我们包括了日期没有过去(即未来)或类型不是someType的那些行。

->where('row_type', '!=', 'someType')->orWhere('date', '>', Carbon::now())

如果您还有其他条件,并且包括orWhere会使这些情况更糟,则应为此使用嵌套:

// ...other wheres...
->where(function($query) {
    $query->where('date', '>', Carbon::now())->orWhere('row_type', '!=', 'someType');
})
->where( // ...other wheres...

我将尝试遍历SQL以证明它可行。

CREATE TABLE my_table(Id integer PRIMARY KEY, row_type text, date date);

/* First row is someType and past - it should be excluded */
INSERT INTO my_table VALUES(1,'someType', '2019-03-01');
INSERT INTO my_table VALUES(2,'someType', '2019-03-31');
INSERT INTO my_table VALUES(3,'otherType', '2019-03-01');
INSERT INTO my_table VALUES(4,'otherType', '2019-03-01');
COMMIT;

op中的查询是这样的:

SELECT 'Cases from the OP' as '';
SELECT id, row_type, date 
FROM my_table
WHERE
  CASE
    WHEN row_type = 'someType'
      THEN date > '2019-03-22%'
  END;

/* returns */
2|someType|2019-03-31

它甚至没有做您所说的话。它还排除了row_type不是someType的每一行。这等效于row_type = 'someType' AND date > '2019-03-22'。要排除您所说的内容,您必须使其更加复杂:

SELECT id, row_type, date 
FROM my_table
WHERE
  CASE
    WHEN row_type = 'someType'
      THEN date > '2019-03-22'
    ELSE 1
  END;

/* returns */
2|someType|2019-03-31
3|otherType|2019-03-01
4|otherType|2019-03-01

但是写这个会更简单,更合适(当实际有多个案例时,案例是合适的):

SELECT ' ' as '';
SELECT 'The same using OR' as '';
SELECT id, row_type, date
FROM my_table
WHERE
  (row_type != 'someType' OR date > '2019-03-22');

/* returns */
2|someType|2019-03-31
3|otherType|2019-03-01
4|otherType|2019-03-01

当您说您也想添加其他语句时,我将该条件括在括号中。这就是where(function($q) {$q->...})会做的。