You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android SQLite多条件查询异常:AND/OR组合返回结果不符合预期

问题排查与修复方案

嘿,我一眼就瞅出问题所在了——SQL逻辑运算符的优先级搞混了你的查询条件!

你原本的SQL语句逻辑因为运算符优先级被篡改了:

SELECT * FROM TABLE_NAME WHERE COLUMN_NAME_COUNTRY='xxx' AND COLUMN_NAME_CATEGORY='Local' OR COLUMN_NAME_CATEGORY='NA'

由于AND的优先级高于OR,数据库实际执行的逻辑是:

(匹配指定国家 AND 类别为Local) OR 类别为NA

这就导致两个不符合预期的结果:

  1. 所有类别为NA的数据,不管所属国家是什么,都会被查出来
  2. 若测试数据中NA类别的数据较少,就会呈现出“所有国家的Local类别数据都被返回”的现象——本质是国家筛选条件没有作用到Local类别的全局匹配上

正确的逻辑应该是:指定国家的数据,且类别是Local或NA,所以必须用括号把OR的两个类别条件包裹起来,让数据库先判断类别,再和国家条件做AND运算:

SELECT * FROM TABLE_NAME WHERE COLUMN_NAME_COUNTRY='xxx' AND (COLUMN_NAME_CATEGORY='Local' OR COLUMN_NAME_CATEGORY='NA')

另外,你的代码还有个大隐患:直接拼接字符串生成SQL会导致SQL注入攻击!如果传入的country参数包含单引号(比如O'Neil),会直接导致SQL语法错误,甚至被恶意利用。所以必须改用参数化查询。

修复后的完整代码

public List<AppDataBean> getAllDataForSelectedCountryWithCategory(String country) {
    ArrayList<AppDataBean> dataList = new ArrayList<>();
    SQLiteDatabase db = AppDbHelper.getInstance(context).getWritableDatabase();
    dataList.clear();
    try {
        // 修正SQL逻辑:用括号包裹OR条件,同时用?占位符实现参数化查询
        String sql = "SELECT * FROM " + AppDbConstructor.AppData.TABLE_NAME + 
                     " WHERE " + AppDbConstructor.AppData.COLUMN_NAME_COUNTRY + "=?" +
                     " AND (" + AppDbConstructor.AppData.COLUMN_NAME_CATEGORY + "=? OR " + 
                     AppDbConstructor.AppData.COLUMN_NAME_CATEGORY + "=?)";
        
        // 传入参数数组,避免SQL注入,同时自动处理字符串转义
        Cursor c = db.rawQuery(sql, new String[]{country, "Local", "NA"});
        
        // 简化Cursor遍历:用do-while更直观,无需提前判断count
        if (c.moveToFirst()) {
            do {
                AppDataBean appDataBean = new AppDataBean();
                appDataBean.setCategory(c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_CATEGORY)));
                appDataBean.setUrl(c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_URL)));
                appDataBean.setSource(c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_SOURCE)));
                appDataBean.setIconUrl(c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_ICON_URL)));
                appDataBean.setCountry(c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_COUNTRY)));
                
                Log.d("APP_DB_SOURCE","COLUMN_NAME_SOURCE: "+ c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_URL)) + ", " + c.getString(c.getColumnIndex(AppDbConstructor.AppData.COLUMN_NAME_CATEGORY)));
                dataList.add(appDataBean);
                Log.d("APPDBSOURCE", "LIST_VALUES_ARE" + dataList.get(dataList.size()-1).getCategory() + ", " + dataList.get(dataList.size()-1).getCountry());
            } while (c.moveToNext());
        }
        c.close();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        db.close();
    }
    return dataList;
}

几个关键的改进点

  • 修正SQL逻辑:通过括号强制改变运算顺序,确保国家筛选条件同时作用于Local和NA两个类别
  • 参数化查询:用?作为占位符,传入参数数组,彻底避免SQL注入,同时解决特殊字符转义问题
  • 简化遍历逻辑:用do-while替代原有的for循环,不需要提前获取游标count,代码更简洁高效

内容的提问来源于stack exchange,提问作者Nuwan Withanage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:27:16