Красноречивый Laravel, как я могу исключить строки из запроса, когда строка соответствует 2 условиям? - PullRequest
4 голосов
/ 21 марта 2019

, поэтому я пытаюсь создать красноречивый запрос Laravel. Он немного сложен, имеет множество предложений, все работают хорошо, и запрашивает одну таблицу. Но я хочу добавить определенное условие, описанное ниже.

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

Это условие работает нормально, но я хочу, чтобы это условие применялось только к определенным строкам! Предположим, что условие, к которому я хочу применить приведенное выше условие:

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

Теперь я не хочу фильтровать все строки, где row_type = 'someType', и не все строки, где date> Carbon :: now ().

Я хочу фильтровать только строки с датой> Carbon :: now () WHEN row_type = 'someType'.

Конечно, и 'date', и 'row_type' являются столбцами в моей таблице.

Теперь, чтобы упростить логику, в основном я хочу ИСКЛЮЧИТЬ строки, где оба (date

Возможно ли это сделать в одном запросе в eloquent без вставки raw sql?

Мне удалось воспроизвести мой запрос в формате raw sql:

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

1 Ответ

1 голос
/ 21 марта 2019

Теперь, чтобы упростить логику, я хочу в основном ИСКЛЮЧИТЬ строки, где оба (date

Либо примените формальную булеву логику !(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;

Запрос в операторе:

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->...}) сделает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...