Laravel красноречиво, как я могу исключить строки из запроса, когда строка соответствует 2 условиям?

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

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

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

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

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

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

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

Теперь, чтобы упростить логику, я хочу в основном ИСКЛЮЧИТЬ строки, где оба (date < Carbon::now() AND row_type = 'someType') верны.

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

Я смог воспроизвести свой запрос в необработанном sql:

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

Если комбинации ->where() и ->orWhere() не работают, может быть, подойдет какая-нибудь CASE WHEN ...? Я бы посоветовал посмотреть, сможете ли вы получить желаемый результат в ручном SQL-запросе (используя любую программу БД, которую вы используете), а затем попытаться перевести это на красноречивый.

Tim Lewis 21.03.2019 20:31

Следующее редактирование: в Laravel есть метод whereRaw(), поэтому вы можете перенести этот case when ... end; в этот, и он должен работать в Eloquent.

Tim Lewis 21.03.2019 20:45

Спасибо @TimLewis Поместит это как необработанный sql, если нет возможности сделать это с помощью красноречивых функций.

Ibrahim Chawa 21.03.2019 20:51

Без проблем! Насколько мне известно, в Laravel нет готовой реализации CASE WHEN ..., поэтому я предлагаю подход raw. Возможно, он появился недавно, но я не уверен в этом.

Tim Lewis 21.03.2019 20:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
6
4
3 059
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Now to simplify the logic, what I want to do basically is EXCLUDE rows where both (date < Carbon::now() AND row_type = 'someType') are true.

Либо примените формальную логическую логику !(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->...}) сделал бы.

Это не работает, потому что я не хочу исключать все результаты, где row_type = 'someType'. И если строка не является «someType», я не хочу, чтобы применялся фильтр даты.

Ibrahim Chawa 21.03.2019 20:49

@IbrahimChawa, вот почему это ИЛИ. Первый where включает все строки, которые не являются someType, а второй применяет фильтр даты к оставшимся (те, которые являются someType). Я думаю, что вы просто подходите к своим условиям не с того конца.

Džuris 21.03.2019 20:55

Ну, мой запрос намного сложнее, чем этот пример. У меня есть куча других статей where. Он включает в себя, где row_type в (некоторые другие типы), и я не могу поставить условие, например илиГде дата > сейчас

Ibrahim Chawa 21.03.2019 20:56

См. Комментарий выше, мне нужно было красноречивое предложение WHERE CASE, но, думаю, его нет. В любом случае спасибо.

Ibrahim Chawa 21.03.2019 21:05

Вы можете делать все, что хотите, но я думаю, что все еще могу избавить вас от использования необработанного оператора. Смотрите мой обновленный ответ. Любой оператор CASE можно заменить комбинацией И/ИЛИ. И это легко и читабельно для однократного случая. Может быть, вложенность wheres - это то, чего вам не хватало?

Džuris 21.03.2019 21:46
that's why it's OR. First where includes all rows that are not someType and the second applies date filter to remaining (those that are someType) .. это умственная гимнастика .. это не читается вообще .. ужасный обходной путь, на мой взгляд, я бы предпочел иметь читаемый необработанный sql, чем слишком сильно пытаться с красноречивым
abbood 22.03.2019 05:21

@abbood Я не могу согласиться с тем, что CASE WHEN было бы легче понять, чем ... AND (row_type != some_type OR date > '2019-03-22'). Использование прецедентов для проверки одного условия вводит в заблуждение. Кроме того, SQL-запрос в OP даже не делает того, что требуется, см. мой обновленный ответ.

Džuris 22.03.2019 09:24

Другие вопросы по теме