房间迁移 - 在迁移代码中使用光标(获取行ID)是否安全?

发布于 2025-01-23 14:07:22 字数 1295 浏览 0 评论 0原文

这是我的迁移变化:

基本上重命名,然后根据行ID 更新一些值 其中isnext = 1


我想我需要使用光标,如此答案。因此,我的自动迁移的代码看起来像这样:

// For Auto-Migration
@RenameColumn(tableName = "Notifications", fromColumnName = "isNext", toColumnName = "wasShown")
static class MyAutoMigration implements AutoMigrationSpec {
    @Override
    public void onPostMigrate(@NonNull SupportSQLiteDatabase database) {
        // Invoked once auto migration is done
        Cursor cursor = database.query("SELECT * from Notifications WHERE wasShown = 1");
        String row_id = String.valueOf(cursor.getPosition());
        database.execSQL("UPDATE Notifications SET wasShown = 1 WHERE id < ?", new String[]{row_id});
        database.execSQL("UPDATE Notifications SET wasShown = 0 WHERE id = ?", new String[]{row_id});
        cursor.close();
    }
}

在某种程度上使用这种逻辑在迁移代码中使用这种逻辑?
例如,因为它可能会抛出异常,或者发生其他事情会崩溃。

我以前从未通过老式的光标直接处理过SQL操纵,因此我的印象可能是脆弱的。

This is my migration change:
enter image description here

Basically rename and then update some values based on the row id where isNext = 1.


I suppose I need to use a Cursor as shown in this answer. So my code with auto-migration would look like this:

// For Auto-Migration
@RenameColumn(tableName = "Notifications", fromColumnName = "isNext", toColumnName = "wasShown")
static class MyAutoMigration implements AutoMigrationSpec {
    @Override
    public void onPostMigrate(@NonNull SupportSQLiteDatabase database) {
        // Invoked once auto migration is done
        Cursor cursor = database.query("SELECT * from Notifications WHERE wasShown = 1");
        String row_id = String.valueOf(cursor.getPosition());
        database.execSQL("UPDATE Notifications SET wasShown = 1 WHERE id < ?", new String[]{row_id});
        database.execSQL("UPDATE Notifications SET wasShown = 0 WHERE id = ?", new String[]{row_id});
        cursor.close();
    }
}

Is it in some way "risky" to use such logic in migration code?
For example because it might throw exceptions, or something else happens that would crash the app.

I never worked with direct SQL manipulation through old-school cursors before, so I have the impression this logic might be fragile.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

柒七 2025-01-30 14:07:22

应该没有问题。但是,没有必要,因为无需光标可以进行更新,因为更新可以确定值。

例如,SQL可能是: -

WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;
  • isnext is cte(common Table Expression)并且就像临时桌子一样,名称可以是您想要的,因为它是列的历史名称,因此使用了Isnext。
  • 请注意,以上,即使是两行,也是一个查询。

以下说明了以上: -

DROP TABLE IF EXISTS Notifications;
CREATE TABLE IF NOT EXISTS Notifications (id INTEGER PRIMARY KEY, wasShown INTEGER);
INSERT INTO Notifications (wasShown) VALUES (0),(0),(0),(0),(1),(0),(0),(0),(0),(0);
/* Show the pre-update data */
SELECT * FROM Notifications;

/* Data prepared so the actual UPDATE */
WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;

/* Show the post-update data */
SELECT * FROM Notifications;
/* cleanup demo */
DROP TABLE IF EXISTS Notifications;

上更高的查询结果: -

“在此处输入图像说明”

post-date查询结果: -

“

sqlfiddle.com/#!5/9eecb7/15190“ rel =“ nofollow noreferrer”>这是一个sqlfiddle demo

您的代码可能是: -

// For Auto-Migration
@RenameColumn(tableName = "Notifications", fromColumnName = "isNext", toColumnName = "wasShown")
static class MyAutoMigration implements AutoMigrationSpec {
    @Override
    public void onPostMigrate(@NonNull SupportSQLiteDatabase database) {
        // Invoked once auto migration is done
        database.execSQL("WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1) UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;");

    }
}

There should be no issues. However, there is no need as the UPDATEs could be done without the need for a Cursor as the UPDATE could determine the value.

e.g. the SQL could be:-

WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;
  • isNext is a CTE (Common Table Expression) and is like a temporary table, the name could be whatever you wish, isNext was used as it was the historical name of the column.
  • note that the above, even over two lines, is a single query.

The following demonstrates the above :-

DROP TABLE IF EXISTS Notifications;
CREATE TABLE IF NOT EXISTS Notifications (id INTEGER PRIMARY KEY, wasShown INTEGER);
INSERT INTO Notifications (wasShown) VALUES (0),(0),(0),(0),(1),(0),(0),(0),(0),(0);
/* Show the pre-update data */
SELECT * FROM Notifications;

/* Data prepared so the actual UPDATE */
WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;

/* Show the post-update data */
SELECT * FROM Notifications;
/* cleanup demo */
DROP TABLE IF EXISTS Notifications;

The pre-update query results in :-

enter image description here

The post-date query results in :-

enter image description here

Here's an SQLFiddle Demo

You code could then be :-

// For Auto-Migration
@RenameColumn(tableName = "Notifications", fromColumnName = "isNext", toColumnName = "wasShown")
static class MyAutoMigration implements AutoMigrationSpec {
    @Override
    public void onPostMigrate(@NonNull SupportSQLiteDatabase database) {
        // Invoked once auto migration is done
        database.execSQL("WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1) UPDATE Notifications SET wasShown = CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END;");

    }
}
糖果控 2025-01-30 14:07:22

我不得不适应Miket的好答案,以便在迁移中又有一个用例:
isnext = 1剩下的没有值时,新表中的所有值都必须设置为washown = 1

经过一些反复试验,我进行了以下有条件的逻辑工作,以涵盖我的所有情况:

WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = 
CASE WHEN EXISTS(SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
THEN CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END
ELSE 1 END;

I had to adapt MikeT's great answer to fit one more use-case in my migration:
When there was no value with isNext=1 left in the old table, all values in the new table had to be set to wasShown=1.

After some trial and error I made the following conditional logic work to cover all of my cases:

WITH isNext(id) AS (SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
UPDATE Notifications SET wasShown = 
CASE WHEN EXISTS(SELECT id FROM Notifications WHERE wasShown = 1 LIMIT 1)
THEN CASE WHEN id < (SELECT id FROM isNext) THEN 1 ELSE 0 END
ELSE 1 END;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文