【问题标题】:Android SQLite grop_concat multiple columnAndroid SQLite grop_concat 多列
【发布时间】:2019-01-07 06:14:21
【问题描述】:

我正在尝试在 android 中运行以下查询。当我尝试检索“d”列的值时,它返回 null。我可以得到 a.* 值。 :(

查询:

select a.*,group_concat(b._id || ', ' || b.product_id || ', ' || b.no_of_units || ', ' || b.unit_price || ', ' || b.discount || ', ' || b.discount, '; ') as d
    from transactions a  join transactions b on a._id=b.local_ref_txn_id 
group by a.id

代码:

mCursor = new MyDbHelper(mContext).getReadableDatabase().rawQuery("select group_concat(b._id || ', ' || b.product_id || ', ' || b.no_of_units || ', ' || b.unit_price || ', ' || b.discount || ', ' || b.discount, '; ') as d,a.* \n" +
                "from transactions a left join transactions b on a._id=b.local_ref_txn_id " +
                "group by a._id", null); 

String details  = cursor.getString(cursor.getColumnIndex("d"));

【问题讨论】:

    标签: android sqlite group-concat


    【解决方案1】:

    您上面的代码将无法工作/无法按预期工作,原因是:-

    首先,当您生成的游标名称为 mCursor 时,您尝试访问名称为 cursor 的游标。

    您似乎正在访问以前创建/提取的游标,假设该游标中存在列 d,则该游标很可能具有列 d 的错误数据。

    因此,代码应该是(仅用于纠正上述问题):-

    String details  = mCursor.getString(mCursor.getColumnIndex("d"));
    

    然而,上述操作会失败,并出现

    android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 0
    

    这是因为没有尝试移动到光标内的一行,因此光标位于“第一行之前”的位置(即位置 -1)。

    要更正上述问题,您需要移动到有效行(如果有的话)。假设您将提取任意数量的行,那么您可以使用以下内容处理每一行:-

    private void SO51603383() {
        Cursor mCursor;
        SO51603383DBHelper MyDbHelper = new SO51603383DBHelper(this);
        mCursor = MyDbHelper.getReadableDatabase().rawQuery("select group_concat(b._id || ', ' || b.product_id || ', ' || b.no_of_units || ', ' || b.unit_price || ', ' || b.discount || ', ' || b.discount, '; ') as d,a.* \n" +
                "from transactions a left join transactions b on a._id=b.local_ref_txn_id " +
                "group by a._id", null);
    
        while (mCursor.moveToNext()) {
            String details = mCursor.getString(mCursor.getColumnIndex("d"));
        }
    }
    

    当/如果您在使用 LEFT JOIN 时运行,您可能会得到空值,如下所示:-

    如果连接操作符是“LEFT JOIN”或“LEFT OUTER JOIN”,那么在 ON 或 USING 过滤子句已被应用,额外的一行是 添加到原始左侧输入中每一行的输出 与复合数据集中完全不对应的数据集 (如果有的话)。添加的行在列中包含 NULL 值 通常包含从右侧输入数据集中复制的值。

    SQL As Understood By SQLite - SELECT

    所以你可能想改用 JOIN。

    示例案例

    使用以下作为数据库助手:-

    public class SO51603383DBHelper extends SQLiteOpenHelper {
    
        public static final String DBNAME = "SO51603383.db";
        public static final int DBVERSION = 1;
    
        public static final String TB_TRANSACTIONS = "transactions";
        public static final String COL_TRANSACTIONS_ID = BaseColumns._ID;
        public static final String COl_TRANSACTIONS_NAME = "name";
        public static final String COL_TRANSACTIONS_PRODUCTID = "product_id";
        public static final String COL_TRANSACTIONS_NO_OF_UNITS = "no_of_units";
        public static final String COL_TRANSACTIONS_UNIT_PRICE = "unit_price";
        public static final String COL_TRANSACTIONS_DISCOUNT = "discount";
        public static final String COl_TRANSACTIONS_LOCAL_REF_TXN = "local_ref_txn_id";
    
        SQLiteDatabase mDB;
    
    
        public SO51603383DBHelper(Context context) {
            super(context, DBNAME, null, DBVERSION);
            mDB = this.getWritableDatabase();
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            String crtsql = "CREATE TABLE IF NOT EXISTS " + TB_TRANSACTIONS + "(" +
                    COL_TRANSACTIONS_ID + " INTEGER PRIMARY KEY," +
                    COl_TRANSACTIONS_NAME + " TEXT," +
                    COL_TRANSACTIONS_PRODUCTID + " INTEGER, " +
                    COL_TRANSACTIONS_NO_OF_UNITS + " INTEGER, " +
                    COL_TRANSACTIONS_UNIT_PRICE + " INTEGER, " +
                    COL_TRANSACTIONS_DISCOUNT + " INTEGER, " +
                    COl_TRANSACTIONS_LOCAL_REF_TXN + " INTEGER" +
                    ")";
            db.execSQL(crtsql);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    
        }
    
        public long add(String name, long productid, int units, int price, int discount, long localref) {
            ContentValues cv = new ContentValues();
            cv.put(COl_TRANSACTIONS_NAME,name);
            cv.put(COL_TRANSACTIONS_PRODUCTID,productid);
            cv.put(COL_TRANSACTIONS_NO_OF_UNITS,units);
            cv.put(COL_TRANSACTIONS_UNIT_PRICE,price);
            cv.put(COL_TRANSACTIONS_DISCOUNT,discount);
            cv.put(COl_TRANSACTIONS_LOCAL_REF_TXN,localref);
            return mDB.insert(TB_TRANSACTIONS,null,cv);
        }
    }
    

    使用加载 2 行(参见上面的添加方法):-

        MyDbHelper.add("Test001",1,10,22,3,0);
        MyDbHelper.add("Test002",1,20,24,5,1);
    

    然后运行:-

        mCursor = MyDbHelper.getReadableDatabase().rawQuery(
                "select group_concat(b._id || ', ' || b.product_id || ', ' || b.no_of_units || ', ' || b.unit_price || ', ' || b.discount || ', ' || b.discount, '; ') " +
                        "as d,a.* \n" +
                "from transactions a left join transactions b on a._id=b.local_ref_txn_id " +
                "group by a._id", null);
    
        while (mCursor.moveToNext()) {
            String details = mCursor.getString(mCursor.getColumnIndex("d"));
            Log.d("DETAILS","Column D from query is :- " + details);
        }
    

    导致以下输出到日志(1 行数据,1 行空值):-

    07-31 02:26:21.255 1580-1580/soanswers.soanswers D/DETAILS: Column D from query is :- 2, 1, 20, 24, 5, 5
        Column D from query is :- null
    

    改用:-

        mCursor = MyDbHelper.getReadableDatabase().rawQuery(
                "select group_concat(b._id || ', ' || b.product_id || ', ' || b.no_of_units || ', ' || b.unit_price || ', ' || b.discount || ', ' || b.discount, '; ') " +
                        "as d,a.* \n" +
                        //"from transactions a left join transactions b on a._id=b.local_ref_txn_id " +
                        "from transactions a join transactions b on a._id=b.local_ref_txn_id " +
                "group by a._id", null);
    
        while (mCursor.moveToNext()) {
            String details = mCursor.getString(mCursor.getColumnIndex("d"));
            Log.d("DETAILS","Column D from query is :- " + details);
        }
    

    导致(清除数据库后):-

    07-31 05:56:38.872 2380-2380/soanswers.soanswers D/DETAILS: Column D from query is :- 2, 1, 20, 24, 5, 5
    

    使用第一个代码 (LEFT JOIN) 并第二次运行,从而添加另外两行(除了 _id 值之外的重复),结果是:-

    07-31 05:59:04.095 2440-2440/? D/DETAILS: Column D from query is :- 2, 1, 20, 24, 5, 5; 4, 1, 20, 24, 5, 5
        Column D from query is :- null
        Column D from query is :- null
        Column D from query is :- null
    

    使用第二个(只是加入)代码并运行两次,结果是:-

    07-31 06:05:00.610 2565-2565/soanswers.soanswers D/DETAILS: Column D from query is :- 2, 1, 20, 24, 5, 5; 4, 1, 20, 24, 5, 5
    

    【讨论】:

    • 感谢您的回复。我忘了提到检索是在游标适配器中完成的,因此游标名称和值来自 SQLite2009 Pro。
    • @MashfiqurRahmanAninda 然后最后一节重新 LEFT JOIN 是问题。
    • 我想是这样,但我知道它的价值是存在的。因为它来自 mysql db 与 sqlite db 同步。
    • 可能是问题所在,因为很有可能可以提取许多值和行。您是否尝试过将 LEFT JOIN 更改为 JOIN?如果不是,那么我建议编辑您的问题以包含 SQL 以创建和填充表。然后可以分析/解释实际结果。
    • 可能是我发现了问题,一旦同步了值,local_ref_txn_id 和 _id 尽管它们有值,但在某种程度上不匹配。虽然很奇怪
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多