如何在 JOIN 语句中使用日期时间比较作为条件
How to use Datetime comparison as condition in JOIN statement
上下文:
我有两个实体:Advert
和 Rental
广告
/**
* @ORM\Table(name = "advert")
* @ORM\Entity(repositoryClass = "App\Repository\AdvertRepository")
*/
class Advert
{
/**
* @ORM\OneToMany(targetEntity = "App\Entity\Rental", mappedBy = "advert")
*/
private $rentals;
private $beginDate;
private $endDate;
public function addRental(\App\Entity\Rental $rental)
{
$this->rentals[] = $rental;
$rental->setAdvert($this);
return ($this);
}
public function getRentals()
{
return $this->rentals
}
出租
/**
* @ORM\Table(name = "rental")
* @ORM\Entity(repositoryClass = "App\Repository\RentalRepository")
*/
class Rental
{
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\Advert", inversedBy = "rentals")
*/
private $advert;
/**
* @var \Datetime
*/
private $beginDate;
/**
* @var \Datetime
*/
private $endDate;
public function setAdvert(\App\Entity\Advert $advert)
{
$this->advert = $advert;
return ($this);
}
public function getAdvert()
{
return $this->advert;
}
}
问题:
我正在尝试编写一个存储库方法,该方法可以像提供的广告一样在数据库中获取广告。现在,我想排除在给定时间段内租用的所有广告。这是我试过的:
在广告存储库中:
//This method creates the query builder and use other methods to
//improve the query
public function fetchSearchResult(Advert $advertType)
{
$qb = $this->createQueryBuilder('a');
// Other methods, similar to hasValidPeriods, using other attributes.
// Some of them preform JOIN, successfully. One of them compare dates
// (but no JOIN) also successfully.
// [...]
$this->hasValidRentalPeriods($qb, $advertType->getBeginDate(), $advertType->getEndDate());
return ($qb->getQuery()->getResult());
}
public function hasValidRentalPeriods(QueryBuilder $qb, \Datetime $beginDate, \Datetime $endDate)
{
$qb->leftJoin('a.rentals', 'rental', 'WITH NOT',
'(
(rental.beginDate < :beginDate AND :beginDate < rental.endDate)
OR (rental.beginDate < :endDate AND :endDate < rental.endDate)
OR (:beginDate < rental.beginDate AND rental.endDate <:endDate)
)')
->setParameter('beginDate', $beginDate)
->setParameter('endDate', $endDate)
;
}
通过这个左连接,我希望得到:
- 所有广告均未出租
- 实际租金与广告中提供的日期没有冲突的所有广告
但这并不是 return 预期的结果。我得到了所有没有租金的广告,但也有冲突的广告。此外,删除 NOT 语句不会更改结果。这就是为什么我意识到这里有问题。
之后我尝试使用更简单的连接:
$qb->leftJoin('a.rentals', 'rental', 'WITH NOT',
'(rental.beginDate < :beginDate AND :beginDate < rental.endDate)'
)
这一次我预计会收到所有广告,但租金与开始日期冲突的广告除外。但是我还是收到了所有的广告。
我也尝试按照 this post 中的建议将日期转换为带有 Datetime::format('Y-m-d H:i:s')
的字符串,但我仍然得到相同的结果。
我很确定我滥用了 Datetime 对象之间的比较。另一方面,我已经成功地进行了这样的比较。或者,我的 JOIN 有误?
注意:广告的租金设置正确。
注2:如果需要,您可以在my github
上查看完整代码和测试
试试这个:
public function hasValidRentalPeriods(QueryBuilder $qb, \DateTime $beginDate, \DateTime $endDate)
{
if (!$beginDate OR !$endDate) {
throw new PreconditionRequiredHttpException('You must provide begin and end dates');
}
if ($endDate <= $beginDate) {
throw new \Exception('wrong dates');
}
$qb
->leftJoin('a.rentals', 'rental')
->where('rental.beginDate > :endDate')
->orWhere('rental.endDate < :beginDate')
->orWhere('rental.beginDate IS NULL')
->orWhere('rental.endDate IS NULL')
->setParameter('beginDate', $beginDate->format('Y-m-d H:i:s'))
->setParameter('endDate', $endDate->format('Y-m-d H:i:s'));
}
这将 return 所有在 beginDate-endDate 期间没有租赁的广告
上下文:
我有两个实体:Advert
和 Rental
广告
/**
* @ORM\Table(name = "advert")
* @ORM\Entity(repositoryClass = "App\Repository\AdvertRepository")
*/
class Advert
{
/**
* @ORM\OneToMany(targetEntity = "App\Entity\Rental", mappedBy = "advert")
*/
private $rentals;
private $beginDate;
private $endDate;
public function addRental(\App\Entity\Rental $rental)
{
$this->rentals[] = $rental;
$rental->setAdvert($this);
return ($this);
}
public function getRentals()
{
return $this->rentals
}
出租
/**
* @ORM\Table(name = "rental")
* @ORM\Entity(repositoryClass = "App\Repository\RentalRepository")
*/
class Rental
{
/**
* @ORM\ManyToOne(targetEntity = "App\Entity\Advert", inversedBy = "rentals")
*/
private $advert;
/**
* @var \Datetime
*/
private $beginDate;
/**
* @var \Datetime
*/
private $endDate;
public function setAdvert(\App\Entity\Advert $advert)
{
$this->advert = $advert;
return ($this);
}
public function getAdvert()
{
return $this->advert;
}
}
问题:
我正在尝试编写一个存储库方法,该方法可以像提供的广告一样在数据库中获取广告。现在,我想排除在给定时间段内租用的所有广告。这是我试过的:
在广告存储库中:
//This method creates the query builder and use other methods to
//improve the query
public function fetchSearchResult(Advert $advertType)
{
$qb = $this->createQueryBuilder('a');
// Other methods, similar to hasValidPeriods, using other attributes.
// Some of them preform JOIN, successfully. One of them compare dates
// (but no JOIN) also successfully.
// [...]
$this->hasValidRentalPeriods($qb, $advertType->getBeginDate(), $advertType->getEndDate());
return ($qb->getQuery()->getResult());
}
public function hasValidRentalPeriods(QueryBuilder $qb, \Datetime $beginDate, \Datetime $endDate)
{
$qb->leftJoin('a.rentals', 'rental', 'WITH NOT',
'(
(rental.beginDate < :beginDate AND :beginDate < rental.endDate)
OR (rental.beginDate < :endDate AND :endDate < rental.endDate)
OR (:beginDate < rental.beginDate AND rental.endDate <:endDate)
)')
->setParameter('beginDate', $beginDate)
->setParameter('endDate', $endDate)
;
}
通过这个左连接,我希望得到:
- 所有广告均未出租
- 实际租金与广告中提供的日期没有冲突的所有广告
但这并不是 return 预期的结果。我得到了所有没有租金的广告,但也有冲突的广告。此外,删除 NOT 语句不会更改结果。这就是为什么我意识到这里有问题。
之后我尝试使用更简单的连接:
$qb->leftJoin('a.rentals', 'rental', 'WITH NOT',
'(rental.beginDate < :beginDate AND :beginDate < rental.endDate)'
)
这一次我预计会收到所有广告,但租金与开始日期冲突的广告除外。但是我还是收到了所有的广告。
我也尝试按照 this post 中的建议将日期转换为带有 Datetime::format('Y-m-d H:i:s')
的字符串,但我仍然得到相同的结果。
我很确定我滥用了 Datetime 对象之间的比较。另一方面,我已经成功地进行了这样的比较。或者,我的 JOIN 有误?
注意:广告的租金设置正确。
注2:如果需要,您可以在my github
上查看完整代码和测试试试这个:
public function hasValidRentalPeriods(QueryBuilder $qb, \DateTime $beginDate, \DateTime $endDate)
{
if (!$beginDate OR !$endDate) {
throw new PreconditionRequiredHttpException('You must provide begin and end dates');
}
if ($endDate <= $beginDate) {
throw new \Exception('wrong dates');
}
$qb
->leftJoin('a.rentals', 'rental')
->where('rental.beginDate > :endDate')
->orWhere('rental.endDate < :beginDate')
->orWhere('rental.beginDate IS NULL')
->orWhere('rental.endDate IS NULL')
->setParameter('beginDate', $beginDate->format('Y-m-d H:i:s'))
->setParameter('endDate', $endDate->format('Y-m-d H:i:s'));
}
这将 return 所有在 beginDate-endDate 期间没有租赁的广告