SQL处理 sql转struct
⎯⎯ 前路浩浩荡荡 万物皆可期待

sql转struct

 3766  |   | 


Select
     
说 明

sql转struct



功能介绍

1.支持多种数据库的建表 sql转struct, 其中包含(pg、oracle、mysql)等数据库; 建表语句, 建表语句, 建表语句(重要的说3遍)
2.在转换 sql 的时候, 需要确认下是否需要切换处理类型, 暂时支持3种处理方式(normal, postgresql, oracle), 默认: normal.
说明: 不能在 sql 中包含注释内容(即: -- xxx# xxx); 由于此工具是通过 ; 来分割语句处理. 所有 normal 状态下可以同时处理多个建表语句; postgresqloracle 由于需要解析注释, 只支持单个建表语句.
3.支持自定义过滤不需要的字段, 多个字段通过 , 隔开.
4.默认注入 json tag, 需要多个的时候通过 , 隔开



示例

mysql 建表语句

CREATE TABLE if not exists user (
  id int NOT NULL AUTO_INCREMENT,
  name varchar(10) NOT NULL COMMENT '姓名',
  gender tinyint NOT NULL DEFAULT 0 COMMENT '性别 0-未知 1-男 2-女',
  age int NOT NULL COMMENT '年龄',
  created_date datetime DEFAULT CURRENT_TIMESTAMP,
  updated_date datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
);

处理后

type UserInfo struct {
    Id int32 `json:"id,omitempty"`
    Name string `json:"name,omitempty"` // 姓名
    Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
    Age int32 `json:"age,omitempty"` // 年龄
    CreatedDate string `json:"created_date,omitempty"`
    UpdatedDate string `json:"updated_date,omitempty"`
}

pgsql 建表语句

CREATE TABLE if not exists user (
  id character varying(32) NOT NULL DEFAULT sys_guid(),
  name character varying(10) NOT NULL,
  gender tinyint NOT NULL,
  age tinyint NOT NULL,
  created_date timestamp without time zone DEFAULT now(),
  updated_date timestamp without time zone DEFAULT now(),
  CONSTRAINT user_pkey PRIMARY KEY (id)
);
COMMENT ON TABLE user IS '用户表';
COMMENT ON COLUMN user.id IS '主键';
COMMENT ON COLUMN user.name IS '姓名';
COMMENT ON COLUMN user.gender IS '性别 0-未知 1-男 2-女';
COMMENT ON COLUMN user.age IS '年龄';
COMMENT ON COLUMN user.created_date IS '创建时间';
COMMENT ON COLUMN user.updated_date IS '更新时间';

处理后

type UserInfo struct {
    Id string `json:"id,omitempty"` // 主键
    Name string `json:"name,omitempty"` // 姓名
    Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
    Age int8 `json:"age,omitempty"` // 年龄
    CreatedDate string `json:"created_date,omitempty"` // 创建时间
    UpdatedDate string `json:"updated_date,omitempty"` // 更新时间
}

oracle 建表语句

CREATE TABLE if not exists user (
  id character varying(32) NOT NULL DEFAULT sys_guid(),
  name character varying(10) NOT NULL,
  gender tinyint NOT NULL,
  age tinyint NOT NULL,
  created_date date default sysdate,,
  updated_date date default sysdate,,
  CONSTRAINT user_pkey PRIMARY KEY (id)
);
COMMENT ON TABLE user IS '用户表';
COMMENT ON COLUMN user.id IS '主键';
COMMENT ON COLUMN user.name IS '姓名';
COMMENT ON COLUMN user.gender IS '性别 0-未知 1-男 2-女';
COMMENT ON COLUMN user.age IS '年龄';
COMMENT ON COLUMN user.created_date IS '创建时间';
COMMENT ON COLUMN user.updated_date IS '更新时间';

处理后

type UserInfo struct {
    Id string `json:"id,omitempty"` // 主键
    Name string `json:"name,omitempty"` // 姓名
    Gender int8 `json:"gender,omitempty"` // 性别 0-未知 1-男 2-女
    Age int8 `json:"age,omitempty"` // 年龄
    CreatedDate string `json:"created_date,omitempty"` // 创建时间
    UpdatedDate string `json:"updated_date,omitempty"` // 更新时间
}



自荐 轻量级spellsql-orm



项目背景

1.spellsql 最初是为了能够高效的拼接 sql 和自动打印最终 sql, 最后为了解决繁琐的查询(基于database/sql)和兼顾性能, 实现了轻量的 orm
2.因为工作中用的是 protobuf, 为了更好的适配查询结果, 最终默认按 json 为 orm 的 tag, 同时支持自定义
3.orm 详情, 希望大佬给 start



orm示例

// Man 以下代码都是以此为准
type Man struct {
    Id int32 `json:"id,omitempty"`
    Name string `json:"name,omitempty"`
    Age int32 `json:"age,omitempty"`
    Addr string `json:"addr,omitempty"`
}

新增

m := Man{
    Name: "xue1234",
    Age: 18,
    Addr: "成都市",
}

rows, _ = NewTable(db).Insert(m).Exec()
t.Log(rows.LastInsertId())

修改

m := Man{
    Name: "xue12",
    Age: 20,
    Addr: "测试",
}

rows, _ := NewTable(db).Update(m, "id=?", 7).Exec()
t.Log(rows.LastInsertId())

删除

m := Man{
    Id: 9,
}

rows, _ := NewTable(db).Delete(m).Exec()
t.Log(rows.LastInsertId())

查询

1.支持对查询结果进行回调操作; 对查询的列结果进行反序列化操作
2.可以对结构体 tag 进行别名查询, 即 tag 名与数据库列名不一致的时候, 可以通过指定 tag 别名进行查询
3.其能够高效的处理单表 CURD, 其在查询方面的性能接近原生, 其中做几个性能对比: 原生 >= spellsql-orm > gorm
4.查询结果支持: struct/map/单字段, 数据库返回的 NULL 类型; 不需要处理, orm 会自行处理, 如果传入空类型值会报错(如: sql.NullString)


单结果集查询
var m Man

// 指定查询列
_ = NewTable(db).Select("name,age").From("man").Where("id=?", 1).FindOne(&m)
t.Log(m)

// 根据查询对象解析
_ = NewTable(db).SelectAuto(m).Where("id=?", 1).FindOne(&m)
t.Log(m)

//  对查询结果进行内容修改
_ = NewTable(db).SelectAuto(m).Where("id=?", 1).FindOneFn(&m, func(_row interface{}) error {
    v := _row.(*Man)
    v.Name = "被修改了哦"
    v.Age = 100000
    return nil
})
t.Log(m)


// 基准测试, 以下是在 mac11 pro m1 上测试
func BenchmarkFindOneGorm(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  var m Man
  gdb.Table("man").Find(&m, "id=?", 1)
 }

 // BenchmarkFindOneGorm-8                     16958             66604 ns/op            4364 B/op         78 allocs/op
 // BenchmarkFindOneGorm-8                     18019             66307 ns/op            4365 B/op         78 allocs/op
 // BenchmarkFindOneGorm-8                     17989             66318 ns/op            4365 B/op         78 allocs/op
 // BenchmarkFindOneGorm-8                     18040             66146 ns/op            4365 B/op         78 allocs/op
 // BenchmarkFindOneGorm-8                     18103             66284 ns/op            4365 B/op         78 allocs/op
}

func BenchmarkFindOneQueryRowScan(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  var m Man
  sqlStr := FmtSqlStr("SELECT name,age,addr FROM man WHERE id=?", 1)
  _ = db.QueryRow(sqlStr).Scan(&m.Id, &m.Age, &m.Addr)
 }

 // BenchmarkFindOneQueryRowScan-8             32281             37144 ns/op            1187 B/op         29 allocs/op
 // BenchmarkFindOneQueryRowScan-8             32155             37214 ns/op            1187 B/op         29 allocs/op
 // BenchmarkFindOneQueryRowScan-8             32061             37085 ns/op            1187 B/op         29 allocs/op
 // BenchmarkFindOneQueryRowScan-8             32131             37132 ns/op            1187 B/op         29 allocs/op
 // BenchmarkFindOneQueryRowScan-8             32160             37183 ns/op            1187 B/op         29 allocs/op
}

func BenchmarkFindOneOrm(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  var m Man
  _ = NewTable(db, "man").IsPrintSql(false).Select("name,age,addr").Where("id=?", 1).FindOne(&m)
 }

 // BenchmarkFindOneOrm-8                      31676             38230 ns/op            1329 B/op         32 allocs/op
 // BenchmarkFindOneOrm-8                      31736             37573 ns/op            1329 B/op         32 allocs/op
 // BenchmarkFindOneOrm-8                      31701             37737 ns/op            1329 B/op         32 allocs/op
 // BenchmarkFindOneOrm-8                      31719             37599 ns/op            1329 B/op         32 allocs/op
 // BenchmarkFindOneOrm-8                      31854             37576 ns/op            1329 B/op         32 allocs/op
}

多结果集查询
var m []*Man
// 多结果查询
err := NewTable(db, "man").Select("id,name,age,addr").Where("id>?", 1).FindAll(&m)
if err != nil {
    t.Fatal(err)
}
t.Logf("%+v", m)

// 对结果集进行处理
err := NewTable(db, "man").Select("id,name,age,addr").Where("id>?", 1).FindAll(&m, func(_row interface{}) error {
    v := _row.(*Man)
    if v.Id == 5 {
        v.Name = "test"
    }
    fmt.Println(v.Id, v.Name, v.Age)
    return nil
})
if err != nil {
    t.Fatal(err)
}
t.Logf("%+v", m)


// 基准测试, 以下是在 mac11 pro m1 上测试
func BenchmarkFindAllGorm(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  var m []*Man
  // sqlStr := FmtSqlStr("SELECT * FROM man WHERE id>?", 1)
  gdb.Table("man").Limit(10).Find(&m, "id>?", 1)
  // b.Log(m)
 }

 // BenchmarkFindAllGorm-8             11581             92114 ns/op            8962 B/op        273 allocs/op
 // BenchmarkFindAllGorm-8             12896             91718 ns/op            8962 B/op        273 allocs/op
 // BenchmarkFindAllGorm-8             12811             91760 ns/op            8961 B/op        273 allocs/op
 // BenchmarkFindAllGorm-8             13072             91517 ns/op            8962 B/op        273 allocs/op
 // BenchmarkFindAllGorm-8             13081             91715 ns/op            8962 B/op        273 allocs/op
}

func BenchmarkFindAllQuery(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  sqlStr := FmtSqlStr("SELECT name,age,addr FROM man WHERE id>? LIMIT ?, ?", 1, 0, 10)
  rows, err := db.Query(sqlStr)
  if err != nil {
   return
  }

  var res []*Man
  for rows.Next() {
   var info Man
   var addr sql.NullString
   err = rows.Scan(&info.Name, &info.Age, &addr)
   if err != nil {
    continue
   }
   info.Addr = addr.String
   res = append(res, &info)
  }
  rows.Close()
 }

 // BenchmarkFindAllQuery-8            23402             51492 ns/op            2769 B/op         99 allocs/op
 // BenchmarkFindAllQuery-8            23434             51465 ns/op            2769 B/op         99 allocs/op
 // BenchmarkFindAllQuery-8            22744             52913 ns/op            2769 B/op         99 allocs/op
 // BenchmarkFindAllQuery-8            23089             51675 ns/op            2769 B/op         99 allocs/op
 // BenchmarkFindAllQuery-8            23162             51550 ns/op            2768 B/op         99 allocs/op
}

func BenchmarkFindAllOrm(b *testing.B) {
 b.ResetTimer()
 for i := 0; i < b.N; i++ {
  var m []*Man
  _ = NewTable(db).IsPrintSql(false).Select("name,age,addr").From("man").Where("id>?", 1).Limit(0, 10).FindAll(&m)
 }

 // BenchmarkFindAllOrm-8              21327             57296 ns/op            3235 B/op        115 allocs/op
 // BenchmarkFindAllOrm-8              21588             55743 ns/op            3235 B/op        115 allocs/op
 // BenchmarkFindAllOrm-8              21538             55733 ns/op            3235 B/op        115 allocs/op
 // BenchmarkFindAllOrm-8              21524             56888 ns/op            3235 B/op        115 allocs/op
 // BenchmarkFindAllOrm-8              21366             55844 ns/op            3235 B/op        115 allocs/op
}



最后

欢迎大佬们指正, 同时也希望大佬给 star
gitee: to
github: to