TYPO3 DBAL Querybuilder:嵌套的 SELECT 语句?

Posted

技术标签:

【中文标题】TYPO3 DBAL Querybuilder:嵌套的 SELECT 语句?【英文标题】:TYPO3 DBAL Querybuilder: Nested SELECT statements? 【发布时间】:2021-05-19 11:20:40 【问题描述】:

是否可以使用 DBAL QueryBuilder 构建如下所示的嵌套 SELECT 语句?

SELECT i.id, i.stable_id, i.version, i.title
FROM initiatives AS i
INNER JOIN (
    SELECT stable_id, MAX(version) AS max_version FROM initiatives GROUP BY stable_id
) AS tbl1
ON i.stable_id = tbl1.stable_id AND i.version = tbl1.max_version
ORDER BY i.stable_id ASC

目标是查询包含每个数据集不同版本的外部非 TYPO3 表。仅应呈现具有最高版本号的数据集。数据库如下所示:

id, stable_id, version, [其余数据行]

stable_id是数据集的外部id。 id 是内部自动增量 ID。而version 也会自动递增。

代码示例:

$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
$result = $queryBuilder
    ->select(...$this->select)
    ->from($this->table)
    ->join(
        'initiatives',
        $queryBuilder
            ->select('stable_id, MAX(version) AS max_version' )
            ->from('initiatives')
            ->groupBy('stable_id'),
        'tbl1',
        $queryBuilder->and(
            $queryBuilder->expr()->eq(
                'initiatives.stable_id',
                $queryBuilder->quoteIdentifier('tbl1.stable_id')
            ),
            $queryBuilder->expr()->eq(
                'initiatives.version',
                $queryBuilder->quoteIdentifier('tbl1.max_version')
            )
        )
    )
    ->orderBy('stable_id', 'DESC')

我无法找出 ON ... AND 语句的正确语法。有什么想法吗?

【问题讨论】:

【参考方案1】:

简短回答:这是不可能的,因为要加入的表是动态生成的。相关表达式被反引号,从而导致 SQL 错误。

但是:SQL 查询可以改成下面的基本相同的 SQL 查询:

SELECT i1.id,stable_id, version, title, p.name, l.name, s.name
FROM initiatives i1
WHERE version = (
    SELECT MAX(i2.version)
    FROM initiatives i2
    WHERE i1.stable_id = i2.stable_id
)
ORDER BY stable_id ASC

这可以使用 DBAL queryBuilder 重建:

$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
$result = $queryBuilder
    ->select(...$this->select)
    ->from($this->table)
    ->where(
        $queryBuilder->expr()->eq(
            'initiatives.version',
            '(SELECT MAX(i2.version) FROM initiatives i2 WHERE initiatives.stable_id = i2.stable_id)'
        ),
    ->orderBy('stable_id', 'DESC')
    ->setMaxResults( 50 )
    ->execute();

【讨论】:

【参考方案2】:

Extbase 查询具有JOIN 功能,但在其他方面非常有限。不过,您可以使用自定义 SQL(请参阅 ->statement() here)。

构建复杂查询的更好 API 是 (Doctrine DBAL) QueryBuilder,包括对 JOINsMAX() 等数据库函数和原始表达式 (->addSelectLiteral()) 的支持。请务必阅读直到有趣的ExpressionBuilder。

因此,Extbase 查询对于检索 Extbase(模型)对象很有用。它可以隐式利用其对数据结构的了解来节省一些代码,但只支持相当简单的查询。

(Doctrine DBAL)QueryBuilder 满足所有其他需求。如果需要,您也可以将原始数据转换为 Extbase 模型。 (for example$propertyMapper->convert($data, Job::class))。

我意识到我们缺乏对两者的明确区分,因为它们在某个时候都被称为“QueryBuilder”,但它们完全不同。这就是为什么我喜欢在提到非 Extbase 时添加“Doctrine”。

具有JOIN ON 多个条件的示例。

$q = TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(TYPO3\CMS\Core\Database\ConnectionPool::class)
    ->getQueryBuilderForTable('fe_users');

$res = $q->select('*')
    ->from('tt_content', 'c')
    ->join(
        'c',
        'be_users',
        'bu',
        $q->expr()->andX(
            $q->expr()->eq(
                'c.cruser_id', $q->quoteIdentifier('bu.uid')
            ),
            $q->expr()->comparison(
                '2', '=', '2'
            )
        )
    )
    ->setMaxResults(5)
    ->execute()
    ->fetchAllAssociative();

【讨论】:

对不起,我的错。我实际上想使用 DBAL 查询生成器。我也尝试过使用属性映射,但由于外部表的数据结构不符合 TYPO3 标准而无法成功。 我使用 DBAL 表达式生成器添加了一个无效的代码示例。 运行代码时遇到什么错误? Call to undefined method。我尝试了不同的语法:$queryBuilder->and()、$queryBuilder->logicalAnd()、$queryBuilder->expr()->and()、$queryBuilder->expr()->logicalAnd(),但没有成功.查看源代码似乎表明JOIN .... ON ( ... AND ...) 语句不可能通过 DBAL 查询构建器。对吗? 是的,这是可能的。 ` ->join( 'c', 'be_users', 'bu', $q->expr()->andX( $q->expr()->eq( 'c.cruser_id', $q->quoteIdentifier ('bu.uid')), $q->expr()->comparison('2', '=', '2')))`

以上是关于TYPO3 DBAL Querybuilder:嵌套的 SELECT 语句?的主要内容,如果未能解决你的问题,请参考以下文章

在 Doctrine DBAL 中重用 QueryBuilder

DBAL Querybuilder 未更新

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

TYPO3:使用 TYPO3 Querybuilder 在 OrderBy 中使用 IS NULL 和 COALESCE

具有数组值的 Doctrine DBAL setParameter()

Doctrine DBAL 查询生成器上缺少 insert() 方法