-
Notifications
You must be signed in to change notification settings - Fork 550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add LAST_INSERT_ID to MySQL upsert query #177
Conversation
So we already have functionality in there to utilize the last insert id. I get the feeling you're looking for something else. We're going to need more details on what you're trying to accomplish and what's not working in order to figure out the proper solution. At first glance this doesn't seem necessary. Can you elaborate on what's going on? |
I was trying to do something like this: type Team struct {
ID int
ExternalID int
Name string
Initials string
}
type TeamStore struct {
db *sql.DB
}
func (s TeamStore) SaveTeam(t *Team) error {
o := models.Team{
ExternalID: t.ExternalID,
Name: t.Name,
Initials: t.Initials,
}
err := o.Upsert(s.db, []string{"name", "initials"})
t.ID = o.ID
return err
}
But it kept returning this error:
I noticed that the value of INSERT INTO teams (`external_id`, `name`, `initials`) VALUES (?,?,?) ON DUPLICATE KEY UPDATE `name` = VALUES(`name`),`initials` = VALUES(`initials`) And the query for updating default values that runs immediately after looked like this: SELECT `id` FROM `teams` WHERE `id`=?
0 Then I tried to modify the query to "return" the last insert ID by adding |
@tpisani Sorry I was on vacation. Back now :) So the code I mentioned before is supposed to do this by getting the It's possible it has a bug, but again I don't think Pull Request isn't the answer. Is it possible you can give me the mysql schema involved here for the |
It's OK. 😉 Maybe the problem is the driver I'm using then: https://github.com/go-sql-driver/mysql. Here is the create statement for CREATE TABLE `teams` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`external_id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`initials` varchar(10) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `external_id` (`external_id`)
); Thank you for your time and patience. |
- What ends up happening in this bug is that if there's a second unique column MySQL automatically allows upsert collisions on it, this means that if you have a unique column that was not the id break, and you also didn't have the ID in your struct, lookup of the values would fail (looking up default values), which happens because your struct doesn't have the ID value. - This patch changes it such that it now uses a list of all non-zero unique values as a way to determine what should be used to pull back the value in the case of a collision where the lastinsertid fails us. - Fix #177
A long long time ago, someone opened PR #177 trying to resolve an issue with mysql upsert. I made a fix, but I never actually pulled it into any mainline code for some reason (commit 2372335). This is the same change made to the v3 code. The reason for this change is because mysql can conflict automatically during upsert on any unique column. This makes total sense. However if it does happen to conflict on an insert for which we don't have an ID (which is probably all the time), then when we go to retrieve the record it fails because we don't have an id and we try to look it up using said id. Instead now we look for non-zero unique columns as the way to find the record (which includes the id if it's non-zero). - Fix mysql upsert bug reported in PR #177
Fixed in v3 branch. Sorry for the year delay :) |
It fixes an error caused by a query that uses the last insert ID to populate default values for structs after an upsert query at https://github.com/vattle/sqlboiler/blob/master/templates/17_upsert.tpl#L200, currently using
0
as the ID: