TYPO3 QueryBuilder-如何查找用户的最新记录?

时间:2019-12-21 10:23:58

标签: typo3 doctrine-dbal

这是一个非常明显的数据问题,但是我在任何地方都找不到简单的解决方案。

使用TYPO3 QueryBuilder,如何从每个用户具有多个条目的表中为每个用户选择最新条目?

uid  user_id  value  crdate
1    1        0      123456
2    1        1      123400
3    2        1      123356
4    2        0      123300

我尝试了许多原始SQL方法,并最终基于此解决方案找到了一种可行的方法- How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?

SELECT * 
FROM `tx_tablename` AS `tt` 
INNER JOIN (
    SELECT `uid`, `user_id`, MAX(`crdate`) AS `MaxDateTime` 
    FROM `tx_tablename` 
    GROUP BY `user_id`
) AS `groupedtt` 
ON `tt`.`user_id` = `groupedtt`.`user_id` 
AND `tt`.`crdate` = `groupedtt`.`MaxDateTime` 
WHERE `tt`.`consent_content` = 3

但我看不到如何在QueryBuilder中重现此内容,因为-> join()语句仅接受表名作为参数,而不接受SQL,并且-> join()仅接受一个连接条件,而不接受两个。

是否还有其他人找到了可以在QueryBuilder中使用的解决方案? 非常感谢

3 个答案:

答案 0 :(得分:1)

引用是在TYPO3 QueryBuilder中完成的。您可以直接使用ConcreteQueryBuilder绕过它。

但是,您必须自己引用标识符,否则将引发异常。

这应该可以解决您的伪代码:

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
...
$subQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('tx_tablename');

$subQuery = $subQueryBuilder
  ->select('uid', 'user_id')
  ->from('tx_tablename')
  ->addSelectLiteral(
    $subQueryBuilder->expr()->max('crdate', 'max_crdate')
  )
  ->groupBy('user_id');

$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('tx_tablename');

$queryResult = $queryBuilder
  ->select('a.*')
  ->from('tx_tablename', 'a')
;

$queryBuilder
    ->getConcreteQueryBuilder()
        ->innerJoin(
            $queryBuilder->quoteIdentifier('a'), // !!! important, quote identifier yourself
            '(' . $subQuery->getSQL() . ')',
            $queryBuilder->quoteIdentifier('b'), // !!! important, quote identifier yourself
            $queryBuilder->expr()->andX(
                $queryBuilder->expr()->eq('a.user_id', $queryBuilder->quoteIdentifier('b.user_id')),
                $queryBuilder->expr()->eq('a.crdate', $queryBuilder->quoteIdentifier('b.max_crdate'))
            ) // andX()
        ) // innerJoin()
;

$queryResult = $queryBuilder->execute();

修改1

固定的代码示例。需要quoteIdentifier()而不是createNamedParam()

注意

如果您使用嵌套的selects / subselects AND并使用命名参数,则必须使用最外面的queryBuilder实例来创建命名参数,而不是当前级别的queryBuilder。

答案 1 :(得分:0)

您可能需要一个子查询。请尝试以下操作。

Enter your name: Deepak                                                                                                              
Hello Deepak                                                                                                                         
How are you feeling today? Are you doing Good or Bad? Good                                                                            
Ok Deepak So today you are basically feeling Good. 

但是,现在的代码会在use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; ... $subQueryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('tx_tablename'); $subQuery = $subQueryBuilder ->select('uid', 'user_id') ->from('tx_tablename') ->addSelectLiteral( $subQueryBuilder->expr()->max('crdate', 'max_crdate') ) ->groupBy('user_id'); $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('tx_tablename'); $queryResult = $queryBuilder ->select('a.*') ->from('tx_tablename', 'a') ->innerJoin( 'a', '(' . $subQuery->getSQL() . ')', 'b', $queryBuilder->expr()->andX( $queryBuilder->expr()->eq('a.user_id', $queryBuilder->createNamedParameter('b.user_id', \PDO::PARAM_STR)), $queryBuilder->expr()->eq('a.crdate', $queryBuilder->createNamedParameter('b.max_crdate', \PDO::PARAM_STR)) ) ) ->execute(); 查询内部产生双反引号(`) 。我不确定如何摆脱它们,但是代码显示了这一概念。

答案 2 :(得分:0)

您是对的-您不能在TYPO3的join()innerJoin()leftJoin()rightJoin()中将子查询用作参数,因为使用{ {1}}(请参见GitHub的TYPO3 v10.2源代码)并添加了反引号。

我想知道以下SQL查询是否返回您所追求的结果:

quoteIdentifier()

在这种情况下,Doctrine代码将如下所示:

SELECT `uid`, `user_id`, value, MAX(`crdate`)
FROM `tx_tablename`
GROUP BY `user_id`
HAVING MAX(`crdate`);