本报告主要验证在达梦(DM)、PostgreSQL(PG)和 MySQL 数据库中,实现“全部为真”(BOOL_AND / EVERY)和“存在为真”(BOOL_OR)逻辑的用法,并展示测试过程及结果。同时,针对测试中出现的输出顺序差异进行底层原理分析。
为统一测试标准,三个数据库均使用如下建表和数据插入语句(根据各库语法特性有微小调整):
-- 创建测试表
CREATE TABLE tasks (
user_id INT,
task_name TEXT,
is_completed BOOLEAN
);
-- 插入测试数据
INSERT INTO tasks VALUES
(1, 'Task A', TRUE),
(1, 'Task B', FALSE),
(2, 'Task C', TRUE),
(2, 'Task D', TRUE),
(3, 'Task E', NULL);
注:数据逻辑为 User 1 有完成和未完成;User 2 全部完成;User 3 状态未知(NULL)。
达梦遵循 PostgreSQL 标准,原生支持 EVERY、BOOL_AND 和 BOOL_OR。其中 EVERY 是 BOOL_AND 的别名,两者功能完全一致。
测试 SQL:
SELECT user_id,
EVERY(is_completed) AS all_completed, -- 或使用 BOOL_AND(is_completed)
BOOL_OR(is_completed) AS any_completed
FROM tasks
GROUP BY user_id;
输出结果(达梦):
| user_id | all_completed | any_completed |
|---|---|---|
| 1 | false | true |
| 2 | true | true |
| 3 | null | null |
注:达梦支持直接显示
true/false/null字面量。
PostgreSQL 是这些函数的原始来源,原生支持 BOOL_AND、BOOL_OR 以及别名 EVERY。
测试 SQL:
SELECT user_id,
BOOL_AND(is_completed) AS all_completed,
BOOL_OR(is_completed) AS any_completed
FROM tasks
GROUP BY user_id;
输出结果(PostgreSQL):
| user_id | all_completed | any_completed |
|---|---|---|
| 2 | t | t |
| 1 | f | t |
| 3 | null | null |
注:PG 默认用
t代表 True,f代表 False。且此时输出顺序被打乱,为 2, 1, 3。
MySQL 不支持 EVERY、BOOL_AND 和 BOOL_OR 函数。因为 MySQL 中布尔类型实质是 TINYINT(1)(False 为 0,True 为 1),通常使用聚合函数 MIN() 和 MAX() 来完美平替。
替代原理:
MIN(is_completed) 等价于 EVERY / BOOL_AND:只要组内有一个 0(假),最小值就是 0;只有全为 1(真),最小值为 1。MAX(is_completed) 等价于 BOOL_OR:只要组内有一个 1(真),最大值就是 1。测试 SQL:
SELECT user_id,
MIN(is_completed) AS all_completed,
MAX(is_completed) AS any_completed
FROM tasks
GROUP BY user_id
ORDER BY user_id; -- 此处为了展示清晰,显式加了排序
输出结果(MySQL):
| user_id | all_completed | any_completed |
|---|---|---|
| 1 | 0 | 1 |
| 2 | 1 | 1 |
| 3 | NULL | NULL |
注:MySQL 显示为 0 和 1,若想看 true/false 可在外层嵌套 IF 函数转换。
在上述没有显式排序的测试中,达梦的输出顺序是 1, 2, 3,而 PostgreSQL 的输出顺序是 2, 1, 3。这是因为 SQL 标准中规定:只要没有显式使用 ORDER BY 子句,数据库是不保证返回结果顺序的,顺序是随机的。
底层原因在于查询优化器在处理 GROUP BY 时,使用了不同的算法:
user_id 进行物理排序,然后再进行聚合。因此结果会自然呈现为升序的 1, 2, 3。user_id)进行哈希计算放入内存中的哈希桶。哈希桶的排列顺序由哈希值决定,而不是插入顺序或数字大小,因此打乱了顺序,出现了 2, 1, 3。解决方案:
为了保证在任何数据库下结果顺序一致且符合预期,必须在 SQL 语句结尾加上 ORDER BY user_id。这也是 DBA 和开发人员在编写报表或测试数据时应当遵循的标准规范。
-- 正确且规范的写法:
SELECT user_id,
MIN(is_completed) AS all_completed,
MAX(is_completed) AS any_completed
FROM tasks
GROUP BY user_id
ORDER BY user_id;
文章
阅读量
获赞
