Выберите записи между датами в доктрине 2

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

вариант 1.

$qb->where('e.fecha > ' . $monday->format('Y-m-d'));
$qb->andWhere('e.fecha < ' . $sunday->format('Y-m-d'));

результат (0 записей):

SELECT r0_.id_reservacion AS id_reservacion0, r0_.fecha AS fecha1, r0_.cliente AS cliente2 
FROM reservacion r0_ 
WHERE (r0_.fecha > 2012 - 07 - 16) AND (r0_.fecha < 2012 - 07 - 22)

вариант 2

$qb->add('where', 'e.fecha between 2012-01-01 and 2012-10-10');

результат (0 записей):

SELECT r0_.id_reservacion AS id_reservacion0, r0_.fecha AS fecha1, r0_.cliente AS cliente2 
FROM reservacion r0_ WHERE r0_.fecha 
BETWEEN 2012 - 01 - 01 AND 2012 - 10 - 10

Это моя таблица с текущими записями:

id      fecha            cliente
1   2012-07-16 00:00:00    2    
2   2012-07-16 13:00:00    4    
3   2012-07-22 23:00:00    4

Изменить 1

Чтобы оценить sql, чтобы избежать сомнений, я выполнил этот запрос:

$qb->where('e.fecha > ' . $sunday->format('Y-m-d'));

результат (3 записи):

SELECT r0_.id_reservacion AS id_reservacion0, r0_.fecha AS fecha1, r0_.cliente AS cliente2 

Итак, похоже, что проблема не в sql. ОТ РЕЗЕРВАЦИИ r0_ ГДЕ r0_.fecha > 2012 - 07


person manix    schedule 19.07.2012    source источник
comment
Только вопрос, пока не приедут знатоки - нужно ли делать строки этих дат? Я имею в виду, например, что первый сгенерированный WHERE имеет r0_.fecha > 2012 - 07 -16 - не должен ли он больше походить на r0_.fecha > '2012-07-16' или что-то подобное?   -  person azhrei    schedule 19.07.2012
comment
Полностью согласен с вами. Но взгляните на обновленный пост   -  person manix    schedule 19.07.2012
comment
Хм, хорошо, а что происходит, когда вы все равно цитируете?   -  person azhrei    schedule 19.07.2012
comment
Ну наверняка в свой безумный момент я допустил ошибку или опечатку. Цитирование даты не повлияет на запрос :D (как я думал сначала).   -  person manix    schedule 19.07.2012


Ответы (4)


Вы можете сделать либо…

$qb->where('e.fecha BETWEEN :monday AND :sunday')
   ->setParameter('monday', $monday->format('Y-m-d'))
   ->setParameter('sunday', $sunday->format('Y-m-d'));

or…

$qb->where('e.fecha > :monday')
   ->andWhere('e.fecha < :sunday')
   ->setParameter('monday', $monday->format('Y-m-d'))
   ->setParameter('sunday', $sunday->format('Y-m-d'));
person MacDada    schedule 14.09.2012
comment
+2 за параметры. Не использовать параметры очень опасно, так как иначе Doctrine не сможет их правильно экранировать. - person Harry Mustoe-Playfair; 28.07.2013
comment
Это может нарушить совместимость с некоторыми платформами БД, такими как Microsoft SQL Server, где нет типа Date и все сохраняется в форме Y-m-d H:i:s.000. Вы должны позволить Doctrine выполнить преобразование, определив тип как 3-й параметр setParameter(), например setParameter('monday', $monday, \Doctrine\DBAL\Types\Type::DATE). - person flu; 18.07.2014
comment
Операторы сравнения для имитации BETWEEN — это >= и <=, а не > и <. - person Courtney Miles; 18.12.2017
comment
Обратите внимание, что, хотя BETWEEN и >=/<= логически эквивалентны, вы можете обнаружить, что ваши запросы будут работать лучше в MySQL, когда вы используете BETWEEN - это побуждает планировщика запросов делать лучший выбор в отношении того, как использовать связанные индексы. - person Courtney Miles; 18.12.2017
comment
Вы также можете использовать: ->where($qb->exp()->between('e.fecha', ':monday', ':sunday') - person Matías Navarro Carter; 19.02.2018
comment
@MatíasNavarroCarter : ->where($qb->expr()->between('e.fecha', ':monday', ':sunday') ты пропустил r в expr() - person BendaThierry.com; 13.09.2020

Я считаю, что правильный способ сделать это - использовать выражения построителя запросов:

$now = new DateTimeImmutable();
$thirtyDaysAgo = $now->sub(new \DateInterval("P30D"));
$qb->select('e')
   ->from('Entity','e')
   ->add('where', $qb->expr()->between(
            'e.datefield',
            ':from',
            ':to'
        )
    )
   ->setParameters(array('from' => $thirtyDaysAgo, 'to' => $now));

http://docs.doctrine-project.org/en/latest/reference/query-builder.html#the-expr-class

Изменить. Преимущество этого метода перед любым другим ответом здесь заключается в том, что он не зависит от программного обеспечения базы данных - вы должны позволить Doctrine обрабатывать тип даты, поскольку он имеет уровень абстракции для работы с такими вещами.

Если вы сделаете что-то вроде добавления строковой переменной в форме «Y-m-d», она сломается, например, при переходе на платформу базы данных, отличную от MySQL.

person Harry Mustoe-Playfair    schedule 27.07.2013
comment
Большое спасибо за ответ ... это единственный способ сравнения дат .... ни один из способов, указанных в другом ответе, не работал у меня :) - person Vidhi; 17.08.2015
comment
Спасибо - это действительно единственный по-настоящему независимый от платформы способ сравнения дат в Doctrine. - person Harry Mustoe-Playfair; 17.08.2015
comment
Я согласен, но разве это не должно быть ->setParameters(array(':from' => $thirtyDaysAgo, ...? - person Andresch Serj; 23.03.2016
comment
@AndreschSerj: На самом деле не должно. См. doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/ . - person helvete; 13.06.2016


    EDIT: See the other answers for better solutions

Первоначальные подходы для новичков, которые я предложил, были (opt1):

$qb->where("e.fecha > '" . $monday->format('Y-m-d') . "'");
$qb->andWhere("e.fecha < '" . $sunday->format('Y-m-d') . "'");

И (вариант 2):

$qb->add('where', "e.fecha between '2012-01-01' and '2012-10-10'");

Это было быстро и легко, и сразу же получился оригинальный постер.

Отсюда и принятый ответ.

Согласно комментариям, это неправильный ответ, но легко сделать ошибку, поэтому я оставляю его здесь как «чего не делать!»

person azhrei    schedule 19.07.2012
comment
Я выбрал ваш второй вариант и работает отлично, этот глупый запрос занял весь мой день. Здорово, большое спасибо! - person manix; 19.07.2012
comment
На самом деле это очень неправильный способ сделать это, вы никогда не должны конкатенировать свои переменные прямо в запросе — вместо этого вы должны использовать параметры: docs.doctrine-project.org/projects/doctrine-dbal/en/latest/ - person Harry Mustoe-Playfair; 28.07.2013
comment
хотя это работает, это неправильно и даже опасно, лучше просто удалите ответ вообще... - person NDM; 22.04.2015

Посмотрите, как я форматирую свою дату $jour в параметрах. Это зависит от того, используете ли вы expr()->like или expr()->lte

$qb
        ->select('e')
        ->from('LdbPlanningBundle:EventEntity', 'e')
        ->where(
            $qb->expr()->andX(
                $qb->expr()->orX(
                    $qb->expr()->like('e.start', ':jour1'),
                    $qb->expr()->like('e.end', ':jour1'),
                    $qb->expr()->andX(
                        $qb->expr()->lte('e.start', ':jour2'),
                        $qb->expr()->gte('e.end', ':jour2')
                    )
                ),
                $qb->expr()->eq('e.user', ':user')
            )
        )
        ->andWhere('e.user = :user ')
        ->setParameter('user', $user)
        ->setParameter('jour1', '%'.$jour->format('Y-m-d').'%')
        ->setParameter('jour2', $jour->format('Y-m-d'))
        ->getQuery()
        ->getArrayResult()
    ;
person Laurent Lolo    schedule 16.08.2017