DB2中按两列统计重复行异常:全表查询为何返回空结果?
看起来你的问题出在DATETIME字段的精度差异或者TAG_NAME字段的隐式字符差异上,结合你给出的测试结果,最可能的原因是前者。让我一步步拆解:
1. 核心问题:GROUP BY的分组逻辑和你预期的不一致
你的第一条查询按DATETIME和TAG_NAME分组却返回空,但指定具体值的查询能找到3条重复——这说明当你精确匹配时,这些行被归为一组,但全局GROUP BY时,它们被拆分成了多个不满足COUNT(*) >1的小组。
最可能的原因:DATETIME的小数秒精度
DB2的TIMESTAMP类型(如果你的DATETIME是这个类型)默认支持到微秒(格式如YYYY-MM-DD HH:MI:SS.FFFFFF)。你在WHERE条件里写的'2018-03-23 15:09:30'会被DB2自动转换成2018-03-23 15:09:30.000000来匹配,但表中可能存在其他行,它们的DATETIME值看起来和这个时间一样,实际却带有不同的小数秒(比如2018-03-23 15:09:30.123456)。
这些行在全局GROUP BY时会被当成不同的分组,每个分组的计数可能只有1,所以不会被HAVING COUNT(*) >1筛选出来;但当你用不带小数的时间查询时,只会匹配到秒部分为.0的那3条,所以能看到重复。
次要可能:TAG_NAME的字符隐藏差异
如果TAG_NAME是CHAR类型(而非VARCHAR),它会自动补空格到定义的长度。比如字段定义是CHAR(20),'HOG.613KU201'会被存储为'HOG.613KU201 '(后面带空格)。如果有其他行的TAG_NAME看起来一样,但实际空格数不同(或包含不可见字符),GROUP BY时也会被分成不同的组。
2. 验证和解决方法
方法1:检查DATETIME的实际存储值
执行这条查询,查看目标TAG_NAME对应的所有DATETIME的完整格式:
SELECT DATETIME, CHAR(DATETIME, ISO) AS FULL_DATETIME FROM ML_MEASURE WHERE TAG_NAME = 'HOG.613KU201' ORDER BY DATETIME;
如果结果里出现不同的小数秒,那就是这个问题了。此时可以通过截断小数秒来分组:
SELECT CAST(DATETIME AS TIMESTAMP(0)) AS TRUNCATED_DATETIME, TAG_NAME, COUNT(*) AS DUPLICATES FROM ML_MEASURE GROUP BY CAST(DATETIME AS TIMESTAMP(0)), TAG_NAME HAVING COUNT(*) > 1;
TIMESTAMP(0)会去掉所有小数秒部分,只保留到秒级。
方法2:检查TAG_NAME的实际内容
如果DATETIME没问题,就检查TAG_NAME的长度和实际值:
SELECT TAG_NAME, LENGTH(TAG_NAME) AS TAG_LENGTH FROM ML_MEASURE WHERE DATETIME = '2018-03-23 15:09:30' ORDER BY TAG_NAME;
如果长度不一致,说明有空格或隐藏字符。此时可以用TRIM()处理后再分组:
SELECT DATETIME, TRIM(TAG_NAME) AS CLEAN_TAG_NAME, COUNT(*) AS DUPLICATES FROM ML_MEASURE GROUP BY DATETIME, TRIM(TAG_NAME) HAVING COUNT(*) > 1;
关于行组织表的说明
行组织表本身不会影响GROUP BY的逻辑,所以这个问题和表的组织方式关系不大,不用太担心这一点。
内容的提问来源于stack exchange,提问作者danielo

