> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> 内置 Web SQL UI (`/play`) 中结果排序、筛选和分页的文档

# Web UI 排序、筛选和分页

内置 Web SQL UI (`play.html`，可通过任意 ClickHouse HTTP 端口的 [`/play`](/docs/zh/concepts/features/interfaces/http) 路径访问) 支持按结果列排序、按列值筛选以及分页浏览结果，无需编辑查询。

这些操作均不在浏览器中执行。每次更改都会使用相应的查询构建设置重新运行查询；服务器会将查询包装为派生表，并在外层添加 `ORDER BY`、`WHERE` 和 `LIMIT`，以物化该设置。因此，屏幕上显示的是整个查询排序、筛选和分页后的结果，而非仅重新排列当前页面恰好包含的行。

<div id="sorting">
  ## 排序
</div>

每个列标题右侧都有两个箭头：▲ 按该列对结果进行升序排序，▼ 按降序排序。点击箭头会启用相应的排序并重新运行查询；点击当前已启用方向的箭头会取消该排序，点击另一方向的箭头则会切换到该方向。箭头是真正的按钮，因此键盘用户可以使用 Tab 键切换到它们，并通过键盘激活；每个箭头也会向辅助技术公开其状态 (标题本身带有 `aria-sort`) 。

在具有可悬停指针 (鼠标) 的设备上，只有在鼠标悬停于列标题上或某个箭头获得焦点时才显示箭头，避免平时造成干扰；在不支持悬停的触摸设备及其他粗指针设备上，箭头会始终显示，以便直接点按。参与排序的列即使未悬停也会显示两个箭头：一个让排序状态一目了然，另一个则是因为反转排序方向最可能是下一步操作。

列标题中的每个图标，无论控制哪项功能，显示方式都一致：当该功能未在该列生效时，图标会以低调的颜色显示；一旦生效，便会采用为已生效控件保留的颜色——浅色主题中为洋红色，深色主题中为黄色——并且即使不悬停也会保持显示。低调显示仅减弱色彩，绝不降低透明度，因此图标无论显示在列名上还是单元格的颜色编码上，都不会显得褪色。

<div id="sorting-by-several-columns">
  ### 按多个列排序
</div>

启用新的排序会替换当前排序：此前参与排序的列将被取消，而点击的列将成为唯一的排序键。点击时按住 <kbd>Shift</kbd>，可保留当前生效的排序键，并将该列添加到其后；这正是 `ORDER BY` 使用的顺序——第一个键决定排序，后续每个键用于打破前面键的并列情况。当排序键多于一个时，每个活动箭头还会以右上角标显示其列在该顺序中的位置 (▼¹、▲²、…) 。

对于已是排序键的列，按住 <kbd>Shift</kbd> 只会改变其排序方向，并保留其在排序顺序中的位置。取消某列的排序只会移除该列，其他键将保持不变。

<div id="filtering">
  ## 筛选
</div>

<div id="filtering-from-a-column-header">
  ### 通过列标题筛选
</div>

每个列标题中都有一个漏斗图标，位于排序箭头旁边，显示方式也相同。点击该图标会打开一个输入框，用于输入该列的谓词，右侧紧贴一个应用按钮 (▶)；占位符会提示该列类型所适用的谓词形式——数值列为 `> 10`，字符串列为 `LIKE '%test%'`。输入框在标题单元格内展开，单元格会增加第二行以容纳它；设置过滤器后，过滤器本身也显示在这一行，因此可以在查看过滤器的位置直接编辑它。输入内容为列名后的部分，因此 `> 10` 会变为 `WHERE column > 10`，服务器在此处接受的任何表达式都可以使用——`BETWEEN 1 AND 5`、`IN (1, 2, 3)`、`IS NOT NULL`、`% 2 = 0`。

按下应用按钮 (或 <kbd>Enter</kbd>) 会应用过滤器并重新运行查询；按 <kbd>Esc</kbd>，或在其他任何位置点击或切换选项卡，都会放弃编辑并收起输入框。没有内容可应用时，应用按钮会处于禁用状态——即未设置过滤器的列中显示空输入框时；但对于已设置过滤器的列，即使输入框为空，应用按钮仍保持可用，因为清空输入框后再应用即可移除该过滤器。多个列上的过滤器会通过 `AND` 组合。

<div id="filtering-from-a-cell">
  ### 从单元格筛选
</div>

选择单元格后，如果该列支持按该值筛选，复制图标旁还会显示一个漏斗图标。点击该图标可选择适用的比较方式：

| 值                                               | 可选项                                                    |
| ----------------------------------------------- | ------------------------------------------------------ |
| 数字                                              | `=`, `!=`, `>`, `<`, `>=`, `<=`                        |
| 日期或时间 (`Date`、`Date32`、`DateTime`、`DateTime64`) | `=`, `!=`, `>`, `<`, `>=`, `<=`                        |
| 最多 100 个字符的字符串                                  | `=`, `!=`, `contains` — 空字符串仅提供 `=` 和 `!=`，因为所有字符串都包含它 |
| `Bool`                                          | `true`, `false` — 直接使用这两个值，而非与该单元格的值比较                 |
| `Enum`                                          | `=`, `!=` — 在封闭的名称集合中进行部分匹配并非有用的过滤器                    |
| `NULL`                                          | `IS NULL`, `IS NOT NULL`                               |

选择其中一项会立即生效。日期、时间或枚举将与服务器呈现的原始文本比较，ClickHouse 会将其解析回该列的类型 (枚举则解析为值的名称) 。`contains` 会转换为 `LIKE` 模式，并对值中的 `%` 和 `_` 进行转义，因此会按字面值匹配。值不属于上述类型的单元格——数组、元组、map 或长文本——不会提供菜单；但仍可通过列标题中的输入框筛选该列。

<div id="the-filter-in-effect">
  ### 当前生效的过滤器
</div>

已应用过滤器的列会在列名下方显示其谓词，并会一直显示，确保用户始终知道屏幕上显示的行只是查询结果的子集；其漏斗图标会随之下移至旁边，位于列标题左下角。点击谓词可在原位置重新打开输入框；点击旁边的 ✕ 或应用空输入，都可以移除过滤器。两种操作都会重新运行查询。

每列只能有一个过滤器，无论其从何处设置：从单元设置过滤器会替换列标题输入框之前设置的过滤器，而列标题始终显示当前生效的过滤器。

返回空结果的过滤查询会保留列标题 (而非空结果通常显示的垂直布局) ，以便查看并移除未匹配任何内容的过滤器。

<div id="pagination">
  ## 分页
</div>

结果最多显示 1000 行；如果结果非常宽，显示的行数可能更少。当结果达到此限制而被截断，但仍有更多内容可查看时，表格下方会显示分页器：

```text theme={null}
Page: 1 2 …   Per page: 1000
```

点击页码会将显示限制和该页页码分别设为 [`page`](/docs/zh/reference/settings/session-settings/other#page) 设置，然后重新运行查询；服务器会将页码转换为相应的 `OFFSET`。只要结果仍处于分页状态，分页器就会一直显示，即使每页都恰好填满、不再看起来像被截断。

不会显示总页数，因为总页数未知——统计结果行数意味着需要运行第二个查询。分页器会列出当前页前的十页、当前页和下一页，后面跟着 `…`。点击 `…` 会将其变为可输入任意页码的输入框；输入框失去焦点时会采用输入的页码 (按 <kbd>Enter</kbd> 也会使其失去焦点) 。

仅当当前页已填满时，才会提供下一页。若返回的行数少于该页可容纳的行数，则表示已到达结果末尾，后面不会再有下一页。 (如果结果长度恰好是页面大小的整数倍，仍会提供额外一页，但该页会返回空结果：要区分这种情况，同样需要统计行数。)

`Per page` 显示每页包含的行数，编辑方式相同：点击该值并输入另一个值。它不能超过结果一次可显示的行数——更大的页面会返回随后被表格截断的行，而下一页会从这些行之后开始，因此继续分页会悄然跳过那些从未显示的行；如果输入更大的数值，会按该最大值处理，显示的也将是该值。更改它后会从第一页重新开始，因为采用新大小的页面会包含不同的行。

更改排序或任何过滤器都会回到第一页：两者都会改变结果包含哪些行或行的顺序，因此用户原先所在的页面不再表示结果中的同一部分。

<div id="how-it-is-applied">
  ## 应用方式
</div>

形态会作为 [`order`](/docs/zh/reference/settings/session-settings/other#order)、[`filter`](/docs/zh/reference/settings/session-settings/other#filter)、[`limit`](/docs/zh/reference/settings/session-settings/other#limit) 和 [`page`](/docs/zh/reference/settings/session-settings/other#page) 查询构建设置发送。由于服务器会将它们应用于已解析的查询，而非查询文本，因此无论原查询为何种形式，它们都能与之配合使用：`UNION`、尾随的 `FORMAT` 子句以及查询自身的 `ORDER BY` 和 `LIMIT` 均可正常工作，编辑器中的查询也绝不会被重写。

列名会以带引号的标识符形式传递，因此名称为表达式 (`count()`) 或包含空格的结果列也可作为排序或过滤键。

<div id="when-it-is-available">
  ## 何时可用
</div>

仅对这些设置可调整结果形态的语句提供形态调整功能，即 `SELECT` 和 `UNION` 查询 (包括以 `WITH` 子句或 `FROM` 开头的查询) 。`SHOW`、`DESCRIBE`、`EXISTS` 或 `EXPLAIN` 不支持此功能：这些语句确实会产生表，但相关设置不适用于它们，因此在此提供控件会暗示行具有实际上并不具备的结果。

形态调整仅适用于单条语句的结果，因此不适用于“全部运行”这种多语句执行；其中每条语句都是具有各自列的独立查询。

对于第一页最多只有一行的结果，也不提供此功能：单行无论如何排序都是相同的顺序，过滤器只能保留或移除该行，因此这些控件除了重新运行查询以获取相同的行外无能为力——而空结果甚至没有可移除的行。这也是在此处隐藏[颜色编码](/docs/zh/concepts/features/interfaces/web-ui-color-coding)开关的原因：最多只有一行时，没有可比较的内容。

两类单行结果会保留控件，因为在这些情况下，控件是唯一的恢复途径：

* 已排序或已应用过滤器的结果，其排序必须保持可逆，过滤器必须能够清除——匹配单行的过滤器正是长结果变为短结果的方式，若同时移除控件，用户就会被困在启用该过滤器的状态；
* 因显示限制而被截断的结果，即较长结果的第一页：页面大小受表一次可显示的单元数量限制，因此非常宽的结果可能被截断为单行，而其后的行正是排序和分页用于访问的内容。

形态属于创建它的语句。运行另一条语句时——无论是在编辑查询后，还是将光标移至多语句编辑器中的另一条语句后——都会丢弃该形态，而不会将 `ORDER BY` 或 `WHERE` 应用于新语句可能不存在的列。

它也属于运行该语句时的上下文：所选数据库、发送请求的服务器和用户，以及查询参数的值。更改其中任一项后，相同的文本会指向不同的列——例如切换数据库后的 `SELECT * FROM events`，或编辑参数后的 `SELECT * FROM {tbl:Identifier}`——因此也会丢弃该形态，下一次运行将返回未经形态调整的结果。

<div id="downloading-and-copying">
  ## 下载和复制
</div>

下载会以相同的形态重新执行生成结果的查询，因此导出的文件会包含与屏幕上结果相同的行，且顺序一致。复制则使用已渲染的结果，因此也会保持一致。

<div id="persistence">
  ## 持久化
</div>

形态会保存在页面 URL (`sort_columns`、`filters`、`page` 和 `page_size`) 、浏览器历史记录以及各查询选项卡的结果快照中，因此重新加载页面、共享链接或前进后退时都会保留该形态。由于形态决定了结果行，而不仅仅是其呈现方式，自动运行查询 (`run=1`) 的共享链接会以相同的形态重新运行查询，从而复现结果本身。为保持精简，仅会存储活跃的形态——未应用形态的结果不会向 URL 或历史记录状态添加任何内容。

如上所述，恢复的结果会将其形态绑定到生成该结果的上下文：快照会记录生成这些行时所使用的数据库、连接和参数值，因此更改其中任一项后重新运行语句时，会丢弃该形态，而不会将其应用于不同的结果。

与[颜色编码模式](/docs/zh/concepts/features/interfaces/web-ui-color-coding)和[固定列](/docs/zh/concepts/features/interfaces/web-ui-pinned-columns)一样，形态会按查询选项卡分别保存，因此在一个选项卡中对结果进行排序或筛选，不会重新运行另一个选项卡中的结果。

<div id="limitations">
  ## 限制
</div>

* 如果服务器无法应用某种形态，查询将失败，错误会像其他失败的查询一样显示。随后会丢弃该形态，因为失败后既不会显示可用于清除它的列标题，也不会显示分页器。
* 排序和筛选通过结果中的列名识别列。结果中可能会两次出现相同的列名 (`SELECT 1 AS x, 2 AS x`，或联接了具有相同列名的表) ，这类列无法仅凭名称区分，因此不会提供排序或筛选控件；同一结果中列名唯一的列仍保留这些控件。
* 多列排序需要按住 <kbd>Shift</kbd> 键，因此在触摸设备上不可用；单列排序不受此限制。
* 单行结果的垂直 (转置) 布局没有列标题，因此也没有控件；因此，用户已调整过形态的结果会保留其水平布局。
