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()); } /**