From 0df2a80565b753e8af445145844245f17baae892 Mon Sep 17 00:00:00 2001 From: Yurun Date: Thu, 3 Aug 2023 15:27:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B8=A6=20distinct=20?= =?UTF-8?q?=E7=9A=84=E5=88=86=E9=A1=B5=E6=9F=A5=E8=AF=A2=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=95=B0=E9=87=8F=E8=BF=94=E5=9B=9E=E4=B8=8D?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=20(#571)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复带 distinct 的分页查询器,记录数量返回不正确 * 修复 whereBrackets 返回非数组值时,生成的 SQL 不带括号 * 修复 * 修复 --- doc/components/db/index.md | 9 +- src/Db/Query/Interfaces/IWrapField.php | 20 ++++ src/Db/Query/Query.php | 15 ++- src/Db/Query/Where/WhereBrackets.php | 4 +- src/Db/Query/WrapField.php | 108 ++++++++++++++++++ .../Component/Tests/Db/QueryCurdBaseTest.php | 18 +++ 6 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 src/Db/Query/Interfaces/IWrapField.php create mode 100644 src/Db/Query/WrapField.php diff --git a/doc/components/db/index.md b/doc/components/db/index.md index 57228e53a7..45609131d0 100644 --- a/doc/components/db/index.md +++ b/doc/components/db/index.md @@ -724,11 +724,16 @@ var_dump(json_encode($data)); // 支持序列化 ### 高性能分页查询 -原理: +**原理:** * 先查出记录 id * 再根据 id 查询记录 +**注意:** + +* 仅支持 MySQL 数据库 +* 不支持 DISTINCT 查询 + ```php // 首先准备好查询构建器 $query = Db::query()->from('xxxtable'); @@ -751,8 +756,6 @@ $limit = 10; $result = $pagination->paginate($page, $limit); ``` -> 仅 MySQL 数据库支持 - ## 查询执行 ### 查询记录 diff --git a/src/Db/Query/Interfaces/IWrapField.php b/src/Db/Query/Interfaces/IWrapField.php new file mode 100644 index 0000000000..10785c1c8b --- /dev/null +++ b/src/Db/Query/Interfaces/IWrapField.php @@ -0,0 +1,20 @@ +option->order = []; - $total = (int) $query->count(); + $option = $query->option; + $option->order = []; + if ($option->distinct) + { + $option->field = [ + new WrapField('count(distinct ', $option->field ?: ['*'], ')'), + ]; + $total = (int) $query->select()->getScalar(); + } + else + { + $total = (int) $query->count(); + } } else { diff --git a/src/Db/Query/Where/WhereBrackets.php b/src/Db/Query/Where/WhereBrackets.php index 27e376e23a..8a8392763b 100644 --- a/src/Db/Query/Where/WhereBrackets.php +++ b/src/Db/Query/Where/WhereBrackets.php @@ -89,11 +89,11 @@ public function toStringWithoutLogic(IQuery $query): string $result = $callResult->toStringWithoutLogic($query); $binds = array_merge($binds, $callResult->getBinds()); - return $result; + return '(' . $result . ')'; } else { - return (string) $callResult; + return '(' . $callResult . ')'; } } } diff --git a/src/Db/Query/WrapField.php b/src/Db/Query/WrapField.php new file mode 100644 index 0000000000..f3f1f039cb --- /dev/null +++ b/src/Db/Query/WrapField.php @@ -0,0 +1,108 @@ +wrapLeft = $wrapLeft; + $this->subFields = $subFields; + $this->wrapRight = $wrapRight; + $this->alias = $alias; + } + + public function getSubFields(): array + { + return $this->subFields; + } + + public function setSubFields(array $subFields): void + { + $this->subFields = $subFields; + } + + public function getWrapLeft(): string + { + return $this->wrapLeft; + } + + public function setWrapLeft(string $wrapLeft): void + { + $this->wrapLeft = $wrapLeft; + } + + public function getWrapRight(): string + { + return $this->wrapRight; + } + + public function setWrapRight(string $wrapRight): void + { + $this->wrapRight = $wrapRight; + } + + /** + * {@inheritDoc} + */ + public function toString(IQuery $query): string + { + if (null === $this->alias) + { + $alias = ''; + } + else + { + $alias = ' as ' . $query->fieldQuote($this->alias); + } + if ($this->subFields) + { + $result = []; + $binds = &$this->binds; + foreach ($this->subFields as $k => $v) + { + if (\is_int($k)) + { + if ($v instanceof Field) + { + $field = $v; + } + else + { + $field = new Field(); + $field->setValue($v ?? '', $query); + } + } + else + { + $field = new Field(null, null, $k, $v); + } + $result[] = $field->toString($query); + $fieldBinds = $field->getBinds(); + if ($fieldBinds) + { + $binds = array_merge($binds, $fieldBinds); + } + } + + $result = implode(',', $result); + } + else + { + $result = parent::toString($query); + } + + return $this->wrapLeft . $result . $this->wrapRight . $alias; + } +} diff --git a/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php b/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php index a3b8125d86..ab9286a1c9 100644 --- a/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php +++ b/tests/unit/Component/Tests/Db/QueryCurdBaseTest.php @@ -186,6 +186,24 @@ public function testPaginate(array $args): void $this->assertEquals($expectedData['total'], $result->getTotal()); $this->assertEquals($expectedData['limit'], $result->getLimit()); $this->assertEquals($expectedData['page_count'], $result->getPageCount()); + + // distinct + $result = $query->distinct()->field('member_id')->from($this->tableArticle)->paginate(1, 1); + $expectedData = [ + 'list' => [ + [ + 'member_id' => 0, + ], + ], + 'limit' => 1, + 'total' => 1, + 'page_count' => 1, + ]; + $this->assertEquals($expectedData, $result->toArray()); + $this->assertEquals($expectedData['list'], $result->getList()); + $this->assertEquals($expectedData['total'], $result->getTotal()); + $this->assertEquals($expectedData['limit'], $result->getLimit()); + $this->assertEquals($expectedData['page_count'], $result->getPageCount()); } /**