Your Question
Hi How add a FROM clause on update to use PostgreSQL join ability on update? I don't wanna use sub-query or separate query because of performance.
UPDATE income
SET amount = 1000, status = 0, ..., ..., ..., ..., ..., ..., ..., ...
FROM account
WHERE income.id = 1 AND income.account_id = account.id AND account.user_id = 200
https://stackoverflow.com/questions/7869592/how-to-do-an-update-join-in-postgresql
The document you expected this should be explained
https://gorm.io/docs/update.html https://gorm.io/docs/sql_builder.html
Expected answer
db.Select(fields).Omit("id", "created_at", "created_by").From("account").
Where("income.id = ? AND income.account_id = account.id AND account.user_id = ?",
income.id, userID).Model(&Income{}).Updates(&income)
OR
db.Select(fields).Omit("id", "created_at", "created_by").Joins("FROM account").
Where("income.id = ? AND income.account_id = account.id AND account.user_id = ?",
income.id, userID).Model(&Income{}).Updates(&income)
OR
db.Clauses(clause.From{Tables: []clause.Table{{Name: "account"}}}).
Select(fields).Omit("id", "created_at", "created_by").
Where("income.id = ? AND income.account_id = account.id AND account.user_id = ?",
income.id, userID).Model(&Income{}).Updates(&income)
OR
db.Clauses(clause.Expr{SQL: "FROM account"}).
Select(fields).Omit("id", "created_at", "created_by").
Where("income.id = ? AND income.account_id = account.id AND account.user_id = ?",
income.id, userID).Model(&Income{}).Updates(&income)
The last one is adds FROM after WHERE
.Updates method adds ID column in WHERE clause that it's ambiguous when using FROM, I prevented it by using .Model(&Income{})
Comment From: github-actions[bot]
This issue has been automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 30 days
Comment From: L1ghtman2k
@Pourqavam hey, have you figured out how to do it? This seems like a very elegant way to perform both validation, and update at the same time
Comment From: L1ghtman2k
There is a resolution to this question in: https://github.com/go-gorm/gorm/issues/4445, now I am not sure if it is the best resolution out there, but it works:
I will modify your 3rd example to make it work:
tx := db.Clauses(clause.From{Tables: []clause.Table{{Name: "account"}}}).
Select(fields).Omit("id", "created_at", "created_by").
Where("income.id = ? AND income.account_id = account.id AND account.user_id = ?",
income.id, userID).Model(&Income{})
tx.Statement.BuildClauses = []string{clause.Update{}.Name(), clause.Set{}.Name(), clause.From{}.Name(), clause.Where{}.Name()}
tx.Updates(&income)
Comment From: L1ghtman2k
Also, just in case you need to dynamically figure out the table name, this may help: https://github.com/go-gorm/gorm/issues/3603#issuecomment-709883403
Comment From: L1ghtman2k
In case of a simple retrieval, like select, the following query might work:
prop := &property.Property{}
tx2 := db.Debug().Select(fmt.Sprintf("%s.*", propertyTableName)).Clauses(clause.From{Tables: []clause.Table{{Name: serviceTableName}, {Name: hostTableName}, {Name: teamTableName}, {Name: propertyTableName}}}).
Where(fmt.Sprintf("%s.id = %s.host_id AND %s.id = %s.service_id AND %s.key = ? AND %s.service_id = ? AND %s.id = ?",hostTableName,serviceTableName,serviceTableName,propertyTableName,propertyTableName,propertyTableName,teamTableName),
"Username", uuid.FromStringOrNil("ff783e2b-ddd2-4d24-82ee-53f58c1be716"),uuid.FromStringOrNil("03302d0b-c28d-444a-9b9b-0440c3d711e3")).First(prop)
if tx2.Error != nil {
panic(tx2.Error)
}
fmt.Println(*prop.Value)
Retreiving values of the specific table only:
Select(fmt.Sprintf("%s.*", propertyTableName)).
Listing multiple tables to be retrieved from:
Clauses(clause.From{Tables: []clause.Table{{Name: serviceTableName}, {Name: hostTableName}, {Name: teamTableName}, {Name: propertyTableName}}}).
Comment From: pourqavam
@Pourqavam hey, have you figured out how to do it? This seems like a very elegant way to perform both validation, and update at the same time
Hi
No, I did it manually to create the query dynamically and by using Exec method, but thank you for your workaround.
I think it can be easier if GORM does something like that internally.
Comment From: jinzhu
https://github.com/go-gorm/gorm/issues/4445#issuecomment-855542337
Comment From: jinzhu
https://github.com/go-gorm/gorm/blob/master/statement.go#L56
Comment From: dhalturin
This may be useful to someone if you need to update the value of a field with the value of a field from another table
tx := db.Clauses(clause.From{
Tables: []clause.Table{
{Name: "category_relations"},
},
}).Select("category_id").Omit("updated_at").
Where("category_relations.name = store_products.store_category and store_id = ?", crawlers[crawler]).
Model(&models.StoreProduct{})
tx.Statement.BuildClauses = []string{
clause.Update{}.Name(),
clause.Set{}.Name(),
clause.From{}.Name(),
clause.Where{}.Name(),
}
err := tx.UpdateColumn("category_id", gorm.Expr("category_relations.category_id")).Error
result
UPDATE "store_products"
SET "category_id"=category_relations.category_id
FROM "category_relations"
WHERE
(category_relations.name = store_products.store_category and store_id = 1) AND
"store_products"."deleted_at" IS NULL