Android不同版本SQLite执行UNION ALL查询结果不一致问题排查
核心根源
Android不同版本自带的SQLite版本差异极大:Android 4(Jelly Bean)搭载SQLite 3.7.x,Android 13搭载SQLite 3.39.x,两者在SQL语法兼容性、聚合逻辑、严格模式等方面存在显著差异,这是导致同一SQL语句结果不一致的核心原因。
你的SQL语句存在的关键问题
1. GROUP BY违反SQL标准
第二个子查询中:
SELECT Inventario.codterritorio,Productos.codcajaplastica,0,0,0,0,-cast((SUM(Inventario.stockdisponible)/ AVG(Productos.undporcaja)) as integer) - 1 AS stockdisponible,0,0,0,0,0 FROM Productos, Inventario WHERE Productos.CodBotella = Inventario.codproducto AND Productos.TipoProducto = 1 AND Productos.CodCajaPlastica > 0 AND Productos.CodBotella >0 GROUP BY Productos.codcajaplastica
SELECT中包含Inventario.codterritorio,但GROUP BY仅指定Productos.codcajaplastica。旧版本SQLite处于宽松模式,会随机取分组内某一行的codterritorio值;高版本SQLite默认开启严格模式,这种写法会导致未分组列的取值不确定,甚至触发隐性错误。
2. UNION ALL列匹配不明确
第一个子查询使用select a.* from inventario a...,依赖inventario表的列顺序与第二个子查询完全一致。若表结构存在隐性变化(或不同SQLite版本对列顺序的解析差异),会导致UNION ALL的列对应混乱,最终结果异常。
3. 聚合函数与类型转换的行为差异
高版本SQLite对SUM()、AVG()的NULL处理、整数除法逻辑更严格,cast(...) as integer的截断规则也可能与旧版本不同,进一步放大结果差异。
修复步骤
修正GROUP BY语句
将Inventario.codterritorio加入GROUP BY,或用聚合函数(如MAX(Inventario.codterritorio))包裹,确保每个分组的codterritorio取值唯一确定:GROUP BY Productos.codcajaplastica, Inventario.codterritorio显式指定UNION ALL的所有列
避免使用a.*,改为显式列出所有列,确保两个子查询的列数、顺序、数据类型完全匹配:-- 第一个子查询显式列 SELECT a.codterritorio, a.codproducto, a.stockinicial, a.stockpedidos, a.stockfacturado, a.stockrechazo, a.stockdisponible, a.stockrecargas, a.stockdescargas, a.stockremesas, a.stockdevolucion, a.stockdifinicial_venta FROM inventario a, productos b WHERE a.codproducto = b.codproducto and b.tipoproducto = 1 and a.codproducto in (select c.codcajaplastica from productos c where c.tipoproducto = 1 and a.codproducto = c.codcajaplastica) -- 第二个子查询保持列顺序一致 UNION ALL SELECT Inventario.codterritorio, Productos.codcajaplastica, 0, 0, 0, 0, -cast((SUM(Inventario.stockdisponible)/ AVG(Productos.undporcaja)) as integer) - 1, 0, 0, 0, 0, 0 FROM Productos, Inventario WHERE Productos.CodBotella = Inventario.codproducto AND Productos.TipoProducto = 1 AND Productos.CodCajaPlastica > 0 AND Productos.CodBotella >0 GROUP BY Productos.codcajaplastica, Inventario.codterritorio强制统一SQLite版本
放弃Android内置SQLite,集成独立的SQLite库(如官方sqlite-android扩展),确保所有Android版本使用相同版本的SQLite,从根源消除版本差异。临时兼容方案(不推荐长期使用)
打开数据库后执行以下PRAGMA语句,关闭严格模式:PRAGMA sql_strict = OFF; PRAGMA legacy_alter_table = ON;
补充说明
附查询结果对比图:Android 4与Android 13的查询结果存在明显差异
内容的提问来源于stack exchange,提问作者Marlon J Avila

