# SQL 使用指南

DexSQL 支持只读 SQL，包括 join、子查询、CTE、聚合、窗口和集合运算。在已支持的语言范围内遵循 SQLite 语义，但文本规则有所不同，详见下文。无效或不支持的语句返回结构化错误。

可以从 [DEX 索引与 descriptor](data-model.zh.md)、[表参考](schema.zh.md)或[查询示例](examples.zh.md)开始。具体任务见[函数](functions.zh.md)、[调用者与 override](calls.zh.md)、[注解](annotations.zh.md)和 [DEX 结构查询](advanced.zh.md)。

## 语句与临时结果

`SELECT`、`VALUES` 用于读取数据。`CREATE VIEW`、`CREATE TEMP VIEW` 和 `CREATE TEMP TABLE ... AS SELECT ...` 为中间关系命名。源数据只读，不支持 `INSERT`、`UPDATE`、`DELETE`、`ALTER`、事务或持久 schema 变更。

```sql
CREATE TEMP TABLE app_strings AS
SELECT string_pool_id, string_idx, value
FROM strings WHERE value LIKE '%example%';

SELECT DISTINCT method
FROM method_strings
WHERE value IN (SELECT value FROM app_strings);
```

一次性 CLI 调用中，每条语句使用单独的 `--sql`，定义只在该请求中有效。交互式 CLI 和 MCP 数据集会跨次提交保留定义，直到 `DROP VIEW` / `DROP TABLE`、重定义或会话关闭。`CREATE` 在校验后替换现有会话定义；`IF NOT EXISTS` 保留原定义。所有会话定义（包括 TEMP TABLE）都是 lazy 的，仅在查询需要时读取其行。CLI 的 `--cache NAME=SQL` 遵循相同作用域规则。这些定义不会创建磁盘缓存文件。

## 文本顺序

文本统一按 DEX 的 UTF-16 码元字典序比较，适用于 `ORDER BY`、窗口排序、`<`、`<=`、
`>`、`>=`、`BETWEEN` 和 `MIN`/`MAX`。部分补充平面 Unicode 字符的顺序不同于
SQLite 的 UTF-8 `BINARY` 顺序：例如 U+10000 排在 U+FFFD 前。ASCII 顺序不变。

`BINARY` 精确比较文本；`NOCASE` 先折叠 ASCII 大小写；`RTRIM` 先去除末尾空格
（U+0020）。数值转换、NULL 排位、BLOB 字节顺序不变；`LIKE` 和 `GLOB` 保留各自的模式匹配规则。

DEX 局部 ID 不是跨文件的文本排序键。跨文件排序请直接对文本写 `ORDER BY`；
完整方法 descriptor 的顺序也不一定与 `method_idx` 一致。

## 文本值

DEX 文本在内部保留原始 MUTF-8 字节。查询输出解码为 UTF-8：`C0 80` 变为 U+0000，有效代理对变为一个 Unicode 标量。孤立代理输出为一个 U+FFFD；其他非法字节（包括四字节 UTF-8 序列的每个字节）逐字节输出为 U+FFFD。因此不同的原始值可能显示相同；用 `hex(value)` 查看存储字节。CLI 表格会转义控制字符，MCP 字符串遵循 JSON 转义。

U+0000 是普通字符：文本函数和模式匹配会处理包含内嵌 NUL 的完整值，与 SQLite 中遇到 NUL 即停止的函数不同。`CAST(text AS BLOB)` 暴露原始 MUTF-8，`CAST(blob AS TEXT)` 保留这些字节。有效 DEX 文本中的代理对在 `length`、`substr` 中算一个字符，而排序比较 UTF-16 码元。

## 文本匹配

未指定 `ESCAPE` 时，`%` 匹配任意字符序列，`_` 是**字面下划线**。例如 `LIKE '%SEND_SMS%'` 查找该字面子串。显式指定 `ESCAPE` 后使用 SQLite 风格模式，未转义的 `_` 可以匹配单个字符。

`LIKE` 不区分 ASCII 大小写，`instr` 和 `=` 区分大小写。按意图选择：

| 匹配方式 | 不区分 ASCII 大小写 | 区分大小写 |
| --- | --- | --- |
| 包含 | `value LIKE '%x%'` | `instr(value, 'x') > 0` |
| 前缀 | `value LIKE 'x%'` | `instr(value, 'x') = 1` |
| 后缀 | `value LIKE '%x'` | `substr(value, -length('x')) = 'x'` |
| 完全相等 | `value LIKE 'x'` | `value = 'x'` |

```sql
SELECT 'SEND_SMS' LIKE '%SEND_SMS%';       -- 1
SELECT 'a' LIKE '_';                     -- 0
SELECT 'a' LIKE '_' ESCAPE '!';          -- 1
SELECT 'HTTPS://' LIKE 'https://%';       -- 1
```

## 查询成本

只选择需要的列，展开大规模注解或引用集合前先过滤；重复查询时复用已准备的数据集。API 的结果条数限制约束响应大小，不一定减少执行工作。有些 join 和 `DISTINCT` 查询即使输出条数很少，也可能超过中间结果预算。使用 CLI `--timing` 测量实际 SQL。

需要稳定的结果顺序时，使用带唯一排序键的 `ORDER BY`，例如 `file_id, method_idx`。续页可能重新执行查询，应保持 SQL 和输入不变。

---

Copyright (c) 2026 LSPosed Developers。本文档采用 [MIT 许可证](../license.md)。
