在单个查询中合并多个 sqlite 语句

问题描述 投票:0回答:1

我有一张下表:

文件夹ID 文件夹路径
1 “C:\用户\奥巴马”
2 “C:\用户名”

这里,folderId 是一个自增键。 现在,插入表有以下步骤: a)检查表中是否存在给定的folderPath。 b)如果给定的folderPath存在,则返回该路径的folderId。 c)如果folderPath不存在,则将该folderPath插入表中并返回其folderId(最后插入的rowId)

我想在单个 SQlite 查询中添加上述步骤以获得更好的性能。 我是 sqlite 的新手,因此我们将不胜感激。 谢谢

我尝试为上述步骤创建一个 SQLite 查询。 我的期望是通过单个查询来获得更好的性能。

sql sqlite android-sqlite sqliteopenhelper sqlite-net
1个回答
0
投票

简而言之,您无法在单个查询中完成上述所有操作。 SQLite 一次只能处理一条语句。您始终需要 2 条陈述:-

一个用于插入或不插入,另一个用于查询表以获得id(反之亦然,即先查询然后插入或不插入)。

  • 前者要求文件夹路径有一个唯一的索引(后者在文件夹路径上有索引可能会更有效)。

但是,

SQLiteDatabase
insert
方法在幕后执行插入操作并获取rowid或其别名(其中folderId列是根据您的问题生成的id)。

此外,

SQLiteDatabase
insert
方法使用
INSERT OR IGNORE ....
。因此,如果存在唯一约束冲突,则不会失败。

出于这些原因,使用

SQliteDatabase
的便利
insert
方法以及在folderPath 列上拥有唯一索引可能是最简单的方法。

就性能而言,如果一次执行多个插入,您应该考虑在单个事务中包装插入。

以下是根据您的问题中提供的信息进行的工作演示:-

DBOpenHelper(特别值得注意的是

insertOrNotFolderReturningFolderId
方法)

class DBOpenHelper extends SQLiteOpenHelper {

    /* DATABASE VALUES (constants)*/
    public static final String DATABASE_NAME = "the_database.db";
    public static final int DATABASE_VERSION = 1;
    /* FOLDER TABLKE VALUES (constants) */
    public static final String FOLDER_TABLE_NAME = "folder";
    public static final String FOLDER_TABLE_COLUMN_FOLDERID = "folderId";
    public static final String FOLDER_TABLE_COLUMN_FOLDERPATH = "folderPath";
    /*
        The Table create SQL noting the UNIQUE index on the folderPath column
     */
    private static final String FOLDER_TABLE_CREATE_SQL =
            "CREATE TABLE IF NOT EXISTS " + FOLDER_TABLE_NAME + "(" +
                    FOLDER_TABLE_COLUMN_FOLDERID + " INTEGER PRIMARY KEY " +
                    "," + FOLDER_TABLE_COLUMN_FOLDERPATH + " TEXT UNIQUE " +
                    ")";
    private volatile static DBOpenHelper instance;

    public static DBOpenHelper getInstance(Context context) {
        if (instance==null) {
            instance = new DBOpenHelper(context);
        }
        return instance;
    }
    private DBOpenHelper(Context context) {
        super(context,DATABASE_NAME,null,DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(FOLDER_TABLE_CREATE_SQL);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {

    }

    public long insertOrNotFolderReturningFolderId(String folderPath) {
        long rv;
        ContentValues cv = new ContentValues();
        cv.put(FOLDER_TABLE_COLUMN_FOLDERPATH,folderPath);
        SQLiteDatabase db = this.getWritableDatabase();
        rv = db.insert(FOLDER_TABLE_NAME,null,cv);
        if (rv < 0) {
            /* use the DatabaseUtils longForQuery to get the id (no need to manage a Cursor)*/
            rv = DatabaseUtils.longForQuery(
                    db,
                    "SELECT " + FOLDER_TABLE_COLUMN_FOLDERID +
                            " FROM " + FOLDER_TABLE_NAME +
                            " WHERE " + FOLDER_TABLE_COLUMN_FOLDERPATH + "=?",
                    new String[]{folderPath}
            );
        }
        return rv;
    }
}

实际演示以下活动代码:-

public class MainActivity extends AppCompatActivity {
    DBOpenHelper helper;
    
    /* folders to test (with duplicates on purpose) */
    String[] testlist = new String[]{
            "C:\\Users\\obama",
            "C:\\Users\\biden",
            "C:\\Users\\fred",
            "C:\\Users\\obama",
            "C:\\Users\\biden",
            "C:\\Users\\fred",
            "C:\\Users\\obama"
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        helper = DBOpenHelper.getInstance(this);
        SQLiteDatabase db = helper.getWritableDatabase();
        db.beginTransaction();
        /* insert rows as per the testlist */
        for (String folderPath: testlist) {
            long folderId = helper.insertOrNotFolderReturningFolderId(folderPath);
            Log.d("DBINFO","Folder " + folderPath + " has an ID of " + folderId);
        }
        db.setTransactionSuccessful();
        db.endTransaction();
        /* Extract ALL rows and write to the log */
        Cursor csr = helper.getWritableDatabase().query(DBOpenHelper.FOLDER_TABLE_NAME,null,null,null,null,null,null);
        int folderIdIx = csr.getColumnIndex(DBOpenHelper.FOLDER_TABLE_COLUMN_FOLDERID);
        int folderPathIx = csr.getColumnIndex(DBOpenHelper.FOLDER_TABLE_COLUMN_FOLDERPATH);
        while (csr.moveToNext()) {
            Log.d("DBINFO","FolderID=" + csr.getLong(folderIdIx) + "FolderPath=" + csr.getString(folderPathIx));
        }
        csr.close();
    }
}

结果输出到日志:-

2023-11-01 07:38:22.749 D/DBINFO: Folder C:\Users\obama has an ID of 1
2023-11-01 07:38:22.749 D/DBINFO: Folder C:\Users\biden has an ID of 2
2023-11-01 07:38:22.750 D/DBINFO: Folder C:\Users\fred has an ID of 3
2023-11-01 07:38:22.753 D/DBINFO: Folder C:\Users\obama has an ID of 1
2023-11-01 07:38:22.755 D/DBINFO: Folder C:\Users\biden has an ID of 2
2023-11-01 07:38:22.764 D/DBINFO: Folder C:\Users\fred has an ID of 3
2023-11-01 07:38:22.769 D/DBINFO: Folder C:\Users\obama has an ID of 1


2023-11-01 07:38:22.773 D/DBINFO: FolderID=1FolderPath=C:\Users\obama
2023-11-01 07:38:22.773 D/DBINFO: FolderID=2FolderPath=C:\Users\biden
2023-11-01 07:38:22.773 D/DBINFO: FolderID=3FolderPath=C:\Users\fred

即在测试列表中的 7 次尝试插入中,仅存在 3 行(最后一部分),但已返回相应的文件夹 ID(第一部分)

© www.soinside.com 2019 - 2024. All rights reserved.