我找到了一些经典的"将来"的解决方案,如果它已经存在,我将如何插入新记录或更新一个记录,但我无法让它们在SQLite中工作.
我有一个表定义如下:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
Run Code Online (Sandbox Code Playgroud)
我想要做的是添加一个具有唯一名称的记录.如果名称已存在,我想修改字段.
有人可以告诉我该怎么做?
使用一个MySQL查询时,是否存在一种简单的方法,INSERT当它不存在时,或者UPDATE它是否存在?
我已经编写了一个存储过程,如果存在记录将进行更新,否则它将进行插入.它看起来像这样:
update myTable set Col1=@col1, Col2=@col2 where ID=@ID
if @@rowcount = 0
insert into myTable (Col1, Col2) values (@col1, @col2)
Run Code Online (Sandbox Code Playgroud)
我以这种方式编写它的逻辑是更新将使用where子句执行隐式选择,如果返回0,则插入将发生.
这样做的替代方法是进行选择,然后根据返回的行数进行更新或插入.我认为这是低效的,因为如果要进行更新,将导致2次选择(第一次显式选择调用,第二次隐式更新位置).如果proc要进行插入,那么效率就没有差别.
我的逻辑声音在这里吗?这是如何将插入和更新组合到存储过程中的?
MySQL有这样的东西:
INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;
Run Code Online (Sandbox Code Playgroud)
据我所知,SQLite中不存在此功能,我想知道的是,如果有任何方法可以实现相同的效果而无需执行两个查询.此外,如果无法做到这一点,您更喜欢什么:
我有下表的柜台:
CREATE TABLE cache (
key text PRIMARY KEY,
generation int
);
Run Code Online (Sandbox Code Playgroud)
我想增加其中一个计数器,或者如果相应的行还不存在则将其设置为零.有没有办法在标准SQL中没有并发问题的情况下执行此操作?该操作有时是交易的一部分,有时是分开的.
如果可能的话,SQL必须在SQLite,PostgreSQL和MySQL上不加修改地运行.
搜索产生了一些想法,这些想法要么遇到并发问题,要么特定于数据库:
尝试换INSERT行,UPDATE如果出现错误.不幸的是,INSERT中止当前事务的错误.
UPDATE行,如果没有修改行,则为INSERT新行.
MySQL有一个ON DUPLICATE KEY UPDATE条款.
编辑:感谢所有的好评.看起来保罗是对的,并没有单一,便携的方式来做到这一点.这对我来说非常令人惊讶,因为它听起来像是一个非常基本的操作.
Android的Room持久性库慷慨地包含适用于对象或集合的@Insert和@Update注释.然而,我有一个用例(包含模型的推送通知)需要UPSERT,因为数据可能存在或可能不存在于数据库中.
Sqlite本身没有upsert,并且在这个SO问题中描述了变通方法.鉴于那里的解决方案,如何将它们应用于房间?
更具体地说,如何在Room中实现不会破坏任何外键约束的插入或更新?使用带onConflict = REPLACE的insert将导致onDelete调用该行的任何外键.在我的情况下,onDelete导致级联,重新插入行将导致其他表中的行与外键被删除.这不是预期的行为.
从文档中可以看出,插入或更新的语法是:INSERT OR REPLACE INTO <table> (<columns>) VALUES (<values>),我的问题是有没有合并以下的函数?
public long insert (String table, String nullColumnHack, ContentValues values)
public int update (String table, ContentValues values, String whereClause, String[] whereArgs)
Run Code Online (Sandbox Code Playgroud)
或者必须使用准备好的SQL语句和rawQuery来完成?
在Android中插入或更新的最佳做法是什么?
目前,我使用以下语句在Android设备上的SQLite数据库中创建表.
CREATE TABLE IF NOT EXISTS 'locations' (
'_id' INTEGER PRIMARY KEY AUTOINCREMENT, 'name' TEXT,
'latitude' REAL, 'longitude' REAL,
UNIQUE ( 'latitude', 'longitude' )
ON CONFLICT REPLACE );
Run Code Online (Sandbox Code Playgroud)
最后的conflict-clause导致在完成具有相同坐标的新插入时删除行.在SQLite的文档包含有关冲突条款的进一步信息.
相反,我想保留前面的行,只是更新他们的列.在Android/SQLite环境中执行此操作的最有效方法是什么?
CREATE TABLE声明中的冲突条款.INSERT触发器.ContentProvider#insert.我认为在数据库中处理此类冲突更具性能.此外,我发现很难重写该ContentProvider#insert方法以考虑插入更新方案.这是insert方法的代码:
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long id = db.insert(DatabaseProperties.TABLE_NAME, null, values);
return ContentUris.withAppendedId(uri, id);
}
Run Code Online (Sandbox Code Playgroud)
当数据从后端到达时,我所做的就是按如下方式插入数据.
getContentResolver.insert(CustomContract.Locations.CONTENT_URI, …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试创建一个sqlite数据库,我可以从另一个sqlite数据库导入一个表(无法附加)并向每个列添加一些额外的数据.
因为没有INSERT OR UPDATE我提出这个:
我正在考虑将数据分成两个表并在之后加入它们所以我可以将整个导入转储到一个表中,替换所有更改并分别管理额外数据,因为这不会改变在进口.
第一个表(让我们称之为base_data)看起来像
local_id | remote_id | base_data1 | base_data2 | ...
---------+-----------+------------+------------+----
Run Code Online (Sandbox Code Playgroud)
除了local_id一切都只是远程数据库的镜像(我可能会添加一个同步时间戳,但现在无关紧要).
第二个表看起来很相似,但remote_id设置为外键
remote_id | extra_data1 | extra_data2 | ...
----------+-------------+-------------+----
CREATE TABLE extra_data (
remote_id INTEGER
REFERENCES base_data(remote_id)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED,
extra_data1 TEXT,
extra_data2 TEXT,
/* etc */
)
Run Code Online (Sandbox Code Playgroud)
现在我的想法只是简单的INSERT OR REPLACE INTO base_data ...值,因为我导入的数据库没有同步时间戳或任何东西,我将不得不比较一切,以找出我有什么行UPDATE/什么INSERT.
但这里存在的问题INSERT OR REPLACE是:实际上是一个DELETE后跟a INSERT和删除部分触发外键 …
我想插入或替换_on_condition.如果不满足条件,请勿插入或更换.这可能吗?
对于我的项目,我目前有两个数据收集过程.一个是快速但不能抓住一切.另一个是缓慢但捕获一切.通过快速流程,我几乎可以实时获取数据.由于速度慢,我在一天结束时使用批处理获取数据.
我的问题是:有时快速流程将"完成"一条记录(意味着它不再需要更新)在缓慢的流程之前,以及在夜间批处理过程中的当天晚些时候,"完整"记录将被替换为在慢速流程的批量数据中找到过时的"待定"记录.
我想要的是一个类似于这个伪代码的条件检查:
If(record_is_not_complete or does_not_exist)
{ INSERT or REPLACE; }
Else
{ do_nothing and move_to_the_next; }
Run Code Online (Sandbox Code Playgroud)
如果我从标准INSERT OR REPLACE示例开始:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'COMPLETE', 5);
Run Code Online (Sandbox Code Playgroud)
哪个应该在UserProgress表中输入一行,条目为[1,COMPLETE,5].
如果发生以下情况:
INSERT OR REPLACE INTO UserProgress (id, status, level)
VALUES (1, 'PENDING', 4);
Run Code Online (Sandbox Code Playgroud)
我希望它跳过这个,因为已经有一个完整的记录.
我确定这是一个重复的问题.但它真的吗?这个问题有很多答案,我不确定哪种方法最好.看看我发现的所有这些例子:
我可以尝试添加一个CASE声明,我被告知它等同于一个IF-THEN-ELSE声明.正如本例中所做的那样.
我可以尝试使用SELECT或COALESCE声明VALUES.正如本例中所做的那样.
我甚至可以尝试使用一个SELECT WHERE声明.正如本例中所做的那样.
我可以尝试使用一个LEFT JOIN声明.正如本例中所做的那样.
这对SQLite来说很棒.似乎有多种方法可以为同一只猫皮肤涂抹.我是一个新手我现在很困惑.目前尚不清楚我应该使用哪种方法.
我正在寻找一个可以在一个sql语句中完成的解决方案.
*更新*
我找到了两个交易解决方案.我还在寻找单一的交易解决方案.
这有效,但使用两个事务: …
sqlite ×7
sql ×5
upsert ×4
android ×3
mysql ×3
.net ×1
android-architecture-components ×1
android-room ×1
c# ×1
database ×1
exists ×1
insert ×1
postgresql ×1
sql-server ×1
sql-update ×1