Golang gorm mysql group by json字段合并(干货)

本文介绍GORM框架下如何进行复杂的SQL操作,包括使用原始SQL、参数化查询、执行模式、批量处理记录等高级特性,并展示了如何利用GORM内部的SQL生成器进行定制化查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原始SQL

查询原始 SQLScan

type Result struct { 
  ID    int
   Name string
   Age   int
 }

var result Result 
db.Raw( "从用户中选择 id、姓名、年龄,其中 id = ?" , 3 ). Scan(&result)

db.Raw( "从用户中选择 id、姓名、年龄 WHERE name = ?" , "jinzhu" ).Scan(&result)

var Age int
 db.Raw( "从用户中选择 SUM(年龄),其中角色 = ?" , "admin" ).Scan(&age)

var users []User 
db.Raw( "UPDATE users SET name = ? WHEREage = ? RETURNING id, name" , "jinzhu" , 20 ).Scan(&users)

Exec使用原始 SQL

db.Exec( "DROP TABLE users" ) 
db.Exec( "更新订单 SETshipped_at = ? WHERE id IN ?" , time.Now(), [] int64 { 1 , 2 , 3 })


db.Exec( "UPDATE users SET Money = ? WHERE name = ?" , gorm.Expr( "money * ? + ?" , 10000 , 1 ), "jinzhu" )

注意GORM 允许缓存准备好的语句来提高性能,查看性能了解详细信息

命名参数

GORM 支持使用sql.NamedArg,map[string]interface{}{}或 struct 命名参数,例如:

db.Where( "name1 = @name OR name2 = @name" , sql.Named( "name" , "jinzhu" )).Find(&user) 


db.Where( "name1 = @name OR name2 = @name" , map [ string ] interface {}{ "name" : "jinzhu2" }).First(&result3) 



db.Raw( "SELECT * FROM users WHERE name1 = @name OR name2 = @name2 OR name3 = @name" , 
   sql.Named( "name" , "jinzhu1" ), sql.Named( "name2" , "jinzhu2" )).Find(&user) 


db.Exec( "UPDATE users SET name1 = @name, name2 = @name2, name3 = @name" , 
   sql.Named( "name" , "jinzhunew" ), sql.Named( "name2" , "jinzhunew2" )) 


db.Raw( "SELECT * FROM users WHERE (name1 = @name AND name3 = @name) AND name2 = @name2" , map [ string ]接口{}{ "name" : "jinzhu" , "name2" : "jinzhu2 " }).Find(&user) 
   


type NamedArgument struct {
  名称字符串
  Name2字符串
}

db.Raw( "SELECT * FROM users WHERE (name1 = @Name AND name3 = @Name) AND name2 = @Name2" , 
   NamedArgument{Name: "jinzhu" , Name2: "jinzhu2" }).Find(&user)

试运行模式

生成SQL及其参数而不执行,可用于准备或测试生成的 SQL,查看Session了解详细信息

stmt := db.Session(&gorm.Session{DryRun: true }).First(&user, 1 ).Statement 
stmt.SQL.String() 
 stmt.Vars

ToSQL

返回SQL未执行而生成的。

GORM使用database/sql的参数占位符来构造SQL语句,它会自动转义参数以避免SQL注入,但生成的SQL不提供安全保证,请仅用于调试。

sql := db.ToSQL(func(tx *gorm.DB) *gorm.DB {
  return tx.Model(&User{}).Where("id = ?", 100).Limit(10).Order("age desc").Find(&[]User{})
})
sql

Row & Rows

Get result as *sql.Row

row := db.Table("users").Where("name = ?", "jinzhu").Select("name", "age").Row()
row.Scan(&name, &age)


row := db.Raw("select name, age, email from users where name = ?", "jinzhu").Row()
row.Scan(&name, &age, &email)

Get result as *sql.Rows

rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows()
defer rows.Close()
for rows.Next() {
  rows.Scan(&name, &age, &email)

  
}


rows, err := db.Raw("select name, age, email from users where name = ?", "jinzhu").Rows()
defer rows.Close()
for rows.Next() {
  rows.Scan(&name, &age, &email)

  
}

Checkout FindInBatches for how to query and process records in batch
Checkout Group Conditions for how to build complicated SQL Query

Scan *sql.Rows into struct

Use ScanRows to scan a row into a struct, for example:

rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() 
defer rows.Close()

var user User
for rows.Next() {
  
  db.ScanRows(rows, &user)

  
}

Connection

Run mutliple SQL in same db tcp connection (not in a transaction)

db.Connection(func(tx *gorm.DB) error {
  tx.Exec("SET my.role = ?", "admin")

  tx.First(&User{})
})

Advanced

Clauses

GORM uses SQL builder generates SQL internally, for each operation, GORM creates a *gorm.Statement object, all GORM APIs add/change Clause for the Statement, at last, GORM generated SQL based on those clauses

For example, when querying with First, it adds the following clauses to the Statement

var limit = 1
clause.Select{Columns: []clause.Column{{Name: "*"}}}
clause.From{Tables: []clause.Table{{Name: clause.CurrentTable}}}
clause.Limit{Limit: &limit}
clause.OrderBy{Columns: []clause.OrderByColumn{
  {
    Column: clause.Column{
      Table: clause.CurrentTable,
      Name:  clause.PrimaryKey,
    },
  },
}}

Then GORM build finally querying SQL in the Query callbacks like:

Statement.Build("SELECT", "FROM", "WHERE", "GROUP BY", "ORDER BY", "LIMIT", "FOR")

Which generate SQL:

SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1

You can define your own Clause and use it with GORM, it needs to implements Interface

Check out examples for reference

Clause Builder

For different databases, Clauses may generate different SQL, for example:

db.Offset(10).Limit(5).Find(&users)

Which is supported because GORM allows database driver register Clause Builder to replace the default one, take the Limit as example

Clause Options

GORM defined Many Clauses, and some clauses provide advanced options can be used for your application

Although most of them are rarely used, if you find GORM public API can’t match your requirements, may be good to check them out, for example:

db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(&user)

StatementModifier

GORM provides interface StatementModifier allows you modify statement to match your requirements, take Hints as example

import "gorm.io/hints"

db.Clauses(hints.New("hint")).Find(&User{})

以下是使用Golang GORM进行MySQL递归查询单表的示例代码: ```go package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Category struct { ID int Name string ParentID int Children []Category `gorm:"foreignkey:ParentID"` } func main() { db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { panic(err) } defer db.Close() var categories []Category db.Where("parent_id = ?", 0).Preload("Children").Find(&categories) for _, category := range categories { fmt.Println(category.Name) for _, child := range category.Children { fmt.Println(" ", child.Name) } } } ``` 在这个示例中,我们定义了一个Category结构体,其中包含ID、Name、ParentID和Children字段。Children字段是一个Category类型的切片,用于存储子类别。在结构体中,我们使用了GORM的foreignkey标记来指定ParentID字段是外键,Children字段是通过ParentID字段与Category表关联的。 在main函数中,我们首先使用GORM的Open函数打开MySQL数据库连接。然后,我们定义了一个categories切片,用于存储查询结果。我们使用GORM的Where函数指定ParentID为0,即查询所有顶级类别。然后,我们使用GORM的Preload函数预加载Children字段,以便在查询结果中包含子类别。最后,我们使用GORM的Find函数执行查询,并将结果存储在categories切片中。 最后,我们遍历categories切片,并打印每个类别及其子类别的名称。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值