I'm trying to do the following using expo-sqlite in react-native:
tx.executeSql(`
INSERT INTO composers (
lastName,
firstName,
birthDate,
deathDate
) VALUES (?, ?, ?, ?);
ON CONFLICT(lastName, firstName, birthDate, deathDate) DO
UPDATE SET
lastName = excluded.lastName,
firstName = excluded.firstName,
birthDate = excluded.birthDate,
deathDate = excluded.deathDate
`,
[
composer.lastName,
composer.firstName,
composer.birthDate,
composer.deathDate
], (_, resultSet) => {
//console.log(JSON.stringify(rows));
const insertId = resultSet.insertId ? resultSet.insertId : 0;
console.log("INSRTED COMPOSER")
console.log(insertId)
},
(tx, error) => dbErrorCallback(tx, error)
);
I have a UNIQUE(lastName, firstName, birthDate, deathDate) constraint on the composers table, and I'm getting an error that the unique constraint failed when I'm inserting a composer who already exists. I'm expecting it to move on to the ON CONFLICT DO UPDATE SET part, but it seems like it doesn't, I'm not even getting to the console.log("INSRTED COMPOSER") part.
I tried removing the semicolon after the VALUES (?, ?, ?, ?); part, but then I get a syntax error.
What I'm basically trying to do overall is to insert a composer and then use the row id to get the autoincremented primary key of the composer to do more inserts, OR if the composer already exists, get its primary key to do more inserts. But I can't even get this first part working.
Related
I am just learning SQLDelight and was hoping to find how to add an object with an ID if it doesn't exist already if it does exist then update that current object with the given id.
currently, I am deleting the current object with id, then adding an object and was hoping to reduce this into one simple call.
My current code:
CREATE TABLE Color (
id TEXT NOT NULL,
name TEXT NOT NULL,
hex TEXT NOT NULL
);
getColorWithId:
SELECT * FROM Color
WHERE id = ?;
saveColor:
INSERT OR REPLACE INTO Color (id, name, hex)
VALUES (?, ?, ?);
deleteColorWithId:
DELETE FROM Color
WHERE id = ?;
I was hoping to change it to replace saveColor and deleteColorWithId with something like:
updateColorWithId:
INSERT OR REPLACE INTO Color (id, name, hex)
WHERE id = ?
VALUES (?, ?, ?);
but it doesn't work with this error <insert stmt values real> expected, got 'WHERE'
can anyone help? I can't find anything in the docs.
Your statement saveColor serves as UPSERT command and it works exactly as you wish. You don't need to create another statement.
INSERT OR REPLACE INTO Color (id, name, hex)
VALUES (?, ?, ?);
You must specify PRIMARY KEY on id column and you can use saveColor as updateColorWithId.
You are already there, try something like this:
Check if the record exists. If it does, then update otherwise add a new row. Using named arguments as per documentation would be ideal. https://cashapp.github.io/sqldelight/native_sqlite/query_arguments/
updateOrInsert:
IF EXISTS (SELECT 1 FROM Color WHERE id = :id)
BEGIN
UPDATE Color
SET id = :id,
name = :name,
hex = :hex
WHERE id = :id
END
ELSE
BEGIN
INSERT INTO Color(id, name, hex)
VALUES (:id, :name, :hex);
END
Usage
dbQuery.updateOrInsert(id = BGColor.id, name = bgColor.name, hex = bgColor.hex)
Take a look at this, might be useful REPLACE INTO vs Update
A projectparticipant may be a member of many groups and a group may have many projectparticipants
I'm finding that when I create 2 ProjectParticipants (this works) and then populate the Project.Groups collection with 3 new groups and add the participants to the relevant groups (Group A has participant 1, Group B has participant 2, Group C has participants 1 and 2), I encounter a "StaleStateException - Batch update returned unexpected row count from update; actual row count: 0, expected: 3". I would expect nHibernate to INSERT the new groups but it's running an UPDATE query and balking that they don't exist. It doesn't get as far as assigning the the participants to the groups
Here are the mappings:
//ProjectMap: A Project..
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
HasMany(x => x.Participants)
.Table("ProjectParticipants")
.KeyColumn("ProjectId")
.ApplyFilter(DeletedDateFilter.FilterName)
.Cascade.AllDeleteOrphan()
.Inverse();
HasMany(x => x.Groups)
.Table("ProjectGroups")
.KeyColumn("ProjectId")
.Cascade.AllDeleteOrphan()
.Inverse();
//ProjectParticipantMap: A ProjectParticipant…
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty);
References(x => x.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Groups)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectParticipantId")
.ChildKeyColumn("ProjectGroupId");
//GroupMap: A Group...
Id(e => e.Id).GeneratedBy.Assigned().UnsavedValue(Guid.Empty);
References(e => e.Project)
.Column("ProjectId")
.LazyLoad(Laziness.Proxy);
HasManyToMany(x => x.Participants)
.Table("ProjectGroupParticipants")
.ParentKeyColumn("ProjectGroupId")
.ChildKeyColumn("ProjectParticipantId")
.ApplyChildFilter(DeletedDateFilter.FilterName);
The tables are:
[ProjectParticipants] 1-->M [ProjectGroupParticipants] M<--1 [ProjectGroups]
M M
\---------------->1 [Project] 1<--------------------/
Here are the SQLs being run by nHibernate:
--presume this is adding the first participant - I find him in the db
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--presume this is adding the second participant - I find her in the DB
INSERT INTO ProjectParticipants (CreatedDate, ModifiedDate, DeletedDate, FirstName, LastName, Timezone, Email, Pseudonym, Role, ProjectId, UserId, MobileNumber, Id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--not sure what this is doing
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
--not sure what this operation is for, but at this point in time NO GROUP EXISTs for this project ID
SELECT … FROM ProjectGroups groups0_ WHERE groups0_.ProjectId=?
--not sure what this is for either?
UPDATE Projects SET CreatedDate = ?, ModifiedDate = ?, LogoUrl = ?, LogoFilename = ?, Client = ?, Name = ?, Description = ?, LastAccessedDate = ? WHERE Id = ?
-- I've no idea why this is an UPDATE instead of an INSERT, but it will certainly update 0 rows instead of X, because no groups exist
UPDATE ProjectGroups SET CreatedDate = ?, ModifiedDate = ?, DeletedDate = ?, Name = ?, ProjectId = ? WHERE Id = ?
Exception thrown: 'NHibernate.StaleStateException' in NHibernate.dll
Batch update returned unexpected row count from update; actual row count: 0; expected: 3
[ UPDATE ProjectGroups SET CreatedDate = #p0, ModifiedDate = #p1, DeletedDate = #p2, Name = #p3, ProjectId = #p4 WHERE Id = #p5 ]
So why did nHibernate come to think that its local entity had already ben saved and was hence available to UPDATE? The SQL generated should be an insert, but I'm not sure how it manages sync between local cache and DB to know if entities already exist or not
Slightly puzzled, that this used to work in NH 2.x, but since an upgrade to latest (5.x) this exception has started appearing.
Slightly puzzled, that this used to work in NH 2.x,
Handling of unsaved-value was indeed changed in 5.2 with this pull request.
If I understand correctly this PR fixed some cases where provided unsaved-value mapping was ignored for assigned identifiers.
So it seems you have incorrect unsaved-value mapping for your entities with assigned identifier. From given data it's unclear how your expect NHibernate to determine if entity is transient. With your mapping if Id is not equal to Guid.Empty NHibernate will trigger UPDATE statement for all cascaded entities and it seems that's exact behavior you see.
If you want it to check database when entity is not present in session - set it to "undefined" instead:
Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue("undefined");
If you want it to always save entity - set it to "any".
Read spec with explanations for all other possible values. Also check this similar issue.
I'm mediocre with perl and new to SQL, so excuse any lameness.
I've got a perl script I'm working on that interacts with a database to keep track of users on IRC. From tutorials I've found, I've been able to create the db, create a table within, INSERT a new record, UPDATE a field in that record, and SELECT/find records based on a field.
The problem is, I can only figure out how to UPDATE one field at a time and that seems inefficient.
The code to create the table:
my $sql = <<'END_SQL';
CREATE TABLE seenDB (
id INTEGER PRIMARY KEY,
date VARCHAR(10),
time VARCHAR(8),
nick VARCHAR(30) UNIQUE NOT NULL,
rawnick VARCHAR(100),
channel VARCHAR(32),
action VARCHAR(20),
message VARCHAR(380)
)
END_SQL
$dbh->do($sql);
And to insert a record using values I've determined elsewhere:
$dbh->do('INSERT INTO seenDB (nick, rawnick, channel, action, message, date, time) VALUES (?, ?, ?, ?, ?, ?, ?)', undef, $nickString, $rawnickString, $channelString, $actionString, $messageString, $dateString, $timeString);
So, when the script needs to update, I'd like to update all of these fiends at once, but right now the only thing that works is one at a time, using syntax I got from the tutorial:
$dbh->do('UPDATE seenDB SET time = ? WHERE nick = ?',
undef,
$timeString,
$nickString);
I've tried the following syntaxes for multiple fields, but they fail:
$dbh->do('UPDATE seenDB (rawnick, channel, action, message, date, time) VALUES (?, ?, ?, ?, ?, ?)', undef, $rawnickString, $channelString, $actionString, $messageString, $dateString, $timeString);
and
$dbh->do('UPDATE seenDB SET rawnick=$rawnickString channel=$channelString action=$actionString message=$messageString date=$dateString time=$timeString WHERE nick=$nickString');
Is there a better way to do this?
You can update several fields at once in pretty much the same way as you update a single field, just list them comma separated in the update, something like;
$dbh->do('UPDATE seenDB SET rawnick=?, channel=?, action=?, message=?, date=?, time=? WHERE nick=?',
undef,
$rawnickString,
$channelString,
$actionString,
$messageString,
$dateString,
$timeString,
$nickString
);
I have the following SQL:
INSERT INTO Invite VALUES (NULL,?,(SELECT id FROM User WHERE name = ?),?);
However this doesnt seem to work.
Can anyone tell me what i am doing wrong?
Update
The following php code gives me erro code 1136:
$sql = 'INSERT INTO Invite SELECT NULL, ?, id, ? FROM User WHERE username = ?';
$variables = array($team_id,$_SESSION['User']['id'],$username);
$result = $this->db->prepTemplate($sql, 'iis', $variables);
INSERT INTO Invite
SELECT NULL, ?, id, ?
FROM User
WHERE name = ?
I got a table with 4 fields:
id, int(11), auto increament email, varchar(32) pass, varchar(32)
date_created, date
My question is how my query should look like?
I mean I don't need to insert the first value to id because it's auto increment but I have to insert all of the values..
First of all, I hope you're using PreparedStatements.
Assuming you have a Connection object named conn and two strings email and password...
PreparedStatement stmt = conn.prepareStatement("INSERT INTO table_name(email, pass, date_created) VALUES (?, ?, ?)");
stmt.setString(1, email);
stmt.setString(2, password);
stmt.setDate(3, new Date());
stmt.executeUpdate();
In SQL you can specify which columns you want to set in the INSERT statement:
INSERT INTO table_name(email, pass, date_created) VALUES(?, ?, ?)
You can insert in the format
INSERT INTO YourTable (Your Columns) VALUES (Your Values)
So for e.g.
INSERT INTO Test_Table (email, pass, data_created) VALUES ('john#blah.com', 'pass', to_date(string, format))
Using parameters-tsql; (better to pass values in parameters rather than as strings)
Insert into [YourTableName] (email, pass, date_created)
values (#email, #pass, #date_created)