@ -1,3 +1,32 @@ | |||||
# dbquery | # dbquery | ||||
数据库操作 | |||||
数据库操作 | |||||
## 链式查询使用 | |||||
``` | |||||
查询单条记录 | |||||
map,err := new(Query).Db(dbname).Table(tablename).Where("id=?").Where("name=?").Value(1).Value("test").Find() | |||||
查询列表 | |||||
list,err := new(Query).Db(dbname).Table(tablename).Where("id=?").Where("name=?").Value(1).Value("test").Select() | |||||
条件"或" | |||||
list,err := new(Query).Db(dbname).Table(tablename).Where("id=?").Where("name=?").WhereOr("mobile=?").Value(1).Value("test").Value("22").Select() | |||||
联表查 | |||||
使用Join | |||||
list,err := new(Query).Db(dbname).Table(tablename).Join([]string{jointable,tablename.id=jointable.cid,"LEFT"}).Where("id=?").Where("name=?").Value(1).Value("test").Select() | |||||
更新 | |||||
ret,err := new(Query).Db(dbname).Table(tablename).Data("name=?").Data("depart=?").Value("xxx").Value("test").Update() | |||||
插入 | |||||
ret,err := new(Query).Db(dbname).Table(tablename).Data("name=?").Data("depart=?").Value("xxx").Value("test").Create() | |||||
删除 | |||||
ret,err := new(Query).Db(dbname).Table(tablename).Where("name=?").Where("depart=?").Value("xxx").Value("test").Delete() | |||||
``` |
@ -0,0 +1,939 @@ | |||||
package dbquery | |||||
import ( | |||||
"database/sql" | |||||
"errors" | |||||
"log" | |||||
"strconv" | |||||
"strings" | |||||
"git.tetele.net/tgo/helper" | |||||
) | |||||
var stmt *sql.Stmt | |||||
var err error | |||||
type Query struct { | |||||
dbname string | |||||
table string | |||||
alias string | |||||
title string | |||||
where []string | |||||
where_or []string | |||||
join [][]string //[["tablea as a","a.id=b.id","left"]] | |||||
save_data []map[string]interface{} //批量操作的数据[["title":"a","num":1,],["title":"a","num":1,]] | |||||
upd_field []string // 批量更新时需要更新的字段,为空时按除id外的字段进行更新 | |||||
data []string | |||||
value []interface{} | |||||
orderby string | |||||
groupby string | |||||
having string | |||||
page int | |||||
page_size int | |||||
stmt *sql.Stmt | |||||
conn *sql.DB | |||||
debug bool | |||||
dbtype string | |||||
with [][]string //[[临时表的sql语句,临时表的名称]] | |||||
} | |||||
func NewQuery(t ...string) *Query { | |||||
var conn_type *sql.DB = DB | |||||
var db_type string = "mysql" | |||||
if len(t) > 0 { | |||||
switch t[0] { | |||||
case "mysql": | |||||
conn_type = DB | |||||
db_type = "mysql" | |||||
case "mssql": //sql server | |||||
conn_type = MSDB_CONN | |||||
db_type = "mssql" | |||||
} | |||||
} | |||||
return &Query{ | |||||
conn: conn_type, | |||||
dbtype: db_type, | |||||
} | |||||
} | |||||
func (this *Query) Conn(conn *sql.DB) *Query { | |||||
this.conn = conn | |||||
return this | |||||
} | |||||
func (this *Query) Db(dbname string) *Query { | |||||
this.dbname = dbname | |||||
return this | |||||
} | |||||
func (this *Query) Table(tablename string) *Query { | |||||
this.table = tablename | |||||
return this | |||||
} | |||||
func (this *Query) Alias(tablename string) *Query { | |||||
this.alias = tablename | |||||
return this | |||||
} | |||||
func (this *Query) Title(title string) *Query { | |||||
this.title = title | |||||
return this | |||||
} | |||||
func (this *Query) Page(page int) *Query { | |||||
this.page = page | |||||
return this | |||||
} | |||||
func (this *Query) PageSize(page_num int) *Query { | |||||
this.page_size = page_num | |||||
return this | |||||
} | |||||
func (this *Query) Having(having string) *Query { | |||||
this.having = having | |||||
return this | |||||
} | |||||
func (this *Query) Orderby(orderby string) *Query { | |||||
this.orderby = orderby | |||||
return this | |||||
} | |||||
func (this *Query) Groupby(groupby string) *Query { | |||||
this.groupby = groupby | |||||
return this | |||||
} | |||||
func (this *Query) With(with []string) *Query { | |||||
this.with = append(this.with, with) | |||||
return this | |||||
} | |||||
func (this *Query) Withs(withs [][]string) *Query { | |||||
this.with = append(this.with, withs...) | |||||
return this | |||||
} | |||||
func (this *Query) Where(where string) *Query { | |||||
this.where = append(this.where, where) | |||||
return this | |||||
} | |||||
func (this *Query) Wheres(wheres []string) *Query { | |||||
if len(wheres) > 0 { | |||||
this.where = append(this.where, wheres...) | |||||
} | |||||
return this | |||||
} | |||||
func (this *Query) WhereOr(where string) *Query { | |||||
this.where_or = append(this.where_or, where) | |||||
return this | |||||
} | |||||
func (this *Query) SaveData(value map[string]interface{}) *Query { | |||||
this.save_data = append(this.save_data, value) | |||||
return this | |||||
} | |||||
func (this *Query) SaveDatas(value []map[string]interface{}) *Query { | |||||
this.save_data = append(this.save_data, value...) | |||||
return this | |||||
} | |||||
func (this *Query) UpdField(value string) *Query { | |||||
this.upd_field = append(this.upd_field, value) | |||||
return this | |||||
} | |||||
func (this *Query) UpdFields(value []string) *Query { | |||||
this.upd_field = append(this.upd_field, value...) | |||||
return this | |||||
} | |||||
func (this *Query) Value(value interface{}) *Query { | |||||
this.value = append(this.value, value) | |||||
return this | |||||
} | |||||
func (this *Query) Values(values []interface{}) *Query { | |||||
this.value = append(this.value, values...) | |||||
return this | |||||
} | |||||
func (this *Query) Join(join []string) *Query { | |||||
this.join = append(this.join, join) | |||||
return this | |||||
} | |||||
/** | |||||
* 左连接 | |||||
* 2023/08/10 | |||||
* gz | |||||
*/ | |||||
func (this *Query) LeftJoin(table_name string, condition string) *Query { | |||||
this.join = append(this.join, []string{table_name, condition, "left"}) | |||||
return this | |||||
} | |||||
/** | |||||
* 右连接 | |||||
* 2023/08/10 | |||||
* gz | |||||
*/ | |||||
func (this *Query) RightJoin(table_name string, condition string) *Query { | |||||
this.join = append(this.join, []string{table_name, condition, "right"}) | |||||
return this | |||||
} | |||||
func (this *Query) Data(data string) *Query { | |||||
this.data = append(this.data, data) | |||||
return this | |||||
} | |||||
func (this *Query) Datas(datas []string) *Query { | |||||
this.data = append(this.data, datas...) | |||||
return this | |||||
} | |||||
func (this *Query) Debug(debug bool) *Query { | |||||
this.debug = debug | |||||
return this | |||||
} | |||||
/* | |||||
* 清理上次查询 | |||||
*/ | |||||
func (this *Query) Clean() *Query { | |||||
this.title = "" | |||||
this.where = this.where[0:0] | |||||
this.where_or = this.where_or[0:0] | |||||
this.join = this.join[0:0] | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
this.orderby = "" | |||||
this.groupby = "" | |||||
this.page = 0 | |||||
this.page_size = 0 | |||||
this.save_data = this.save_data[0:0] | |||||
this.upd_field = this.upd_field[0:0] | |||||
this.having = "" | |||||
this.alias = "" | |||||
this.with = this.with[0:0] | |||||
return this | |||||
} | |||||
// 获取表格信息 | |||||
func (this *Query) GetTableInfo(table string) (map[string]interface{}, error) { | |||||
field := []string{ | |||||
"COLUMN_NAME", //字段名 | |||||
"COLUMN_DEFAULT", //默认值 | |||||
"DATA_TYPE", //数据类型 | |||||
"COLUMN_TYPE", //数据类型+长度 | |||||
"COLUMN_COMMENT", //备注 | |||||
"IS_NULLABLE", //是否为空 | |||||
} | |||||
sql := "select `" + strings.Join(field, "`,`") + "` from information_schema.COLUMNS where table_name = ? and table_schema = ?" | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmtSql, err := this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
list, err := StmtForQueryList(stmtSql, []interface{}{table, this.dbname}) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
rows := make([]interface{}, 0, len(list)) | |||||
fieldName := make([]string, 0, len(list)) | |||||
for _, item := range list { | |||||
info := map[string]interface{}{ | |||||
"name": "", | |||||
"column_type": "", | |||||
"is_null": true, | |||||
"data_type": "", | |||||
"comment": "", | |||||
"default": "", | |||||
} | |||||
for _, k := range field { | |||||
index := helper.StrFirstToUpper(k) | |||||
if v, ok := item[index]; ok { | |||||
switch k { | |||||
case "COLUMN_NAME": | |||||
info["name"] = v | |||||
case "COLUMN_DEFAULT": | |||||
info["default"] = v | |||||
case "DATA_TYPE": | |||||
info["data_type"] = v | |||||
case "COLUMN_TYPE": | |||||
info["column_type"] = helper.ToInt64(v) | |||||
case "COLUMN_COMMENT": | |||||
info["comment"] = helper.ToInt64(v) | |||||
case "IS_NULLABLE": | |||||
if v == "NO" { | |||||
info["is_null"] = false | |||||
} | |||||
} | |||||
} | |||||
} | |||||
name := helper.ToStr(info["name"]) | |||||
if name != "" { | |||||
rows = append(rows, info) | |||||
fieldName = append(fieldName, name) | |||||
} | |||||
} | |||||
return map[string]interface{}{ | |||||
"field": fieldName, | |||||
"list": rows, | |||||
}, nil | |||||
} | |||||
// 返回表名 | |||||
func (this *Query) GetTableName(table string) string { | |||||
return getTableName(this.dbname, table) | |||||
} | |||||
// 构造子查询 | |||||
func (this *Query) BuildSelectSql() (map[string]interface{}, error) { | |||||
if this.dbname == "" && this.table == "" { | |||||
return nil, errors.New("参数错误,没有数据表") | |||||
} | |||||
var table = "" | |||||
withSql := "" | |||||
if len(this.with) > 0 { | |||||
var builder strings.Builder | |||||
builder.WriteString("WITH ") | |||||
boo := false | |||||
for k, v := range this.with { | |||||
if len(v) < 2 { | |||||
continue | |||||
} | |||||
if k != 0 { | |||||
builder.WriteString(", ") | |||||
} | |||||
builder.WriteString(v[1]) | |||||
builder.WriteString(" as (") | |||||
builder.WriteString(v[0]) | |||||
builder.WriteString(")") | |||||
boo = true | |||||
} | |||||
if boo { | |||||
builder.WriteString(" ") | |||||
withSql = builder.String() | |||||
} | |||||
} | |||||
if withSql != "" || strings.Contains(this.table, "select ") || strings.HasPrefix(this.table, "(") { | |||||
table = this.table | |||||
} else { | |||||
table = getTableName(this.dbname, this.table, this.dbtype) | |||||
} | |||||
// var err error | |||||
var sql, title string | |||||
if this.title != "" { | |||||
title = this.title | |||||
} else { | |||||
title = "*" | |||||
} | |||||
if this.dbtype == "mssql" { | |||||
if this.page_size > 0 { | |||||
sql = helper.StringJoin(withSql, "select top ", helper.ToStr(this.page_size), " ") | |||||
} else { | |||||
sql = helper.StringJoin(withSql, "select ") | |||||
} | |||||
} else { | |||||
if DB_PROVIDER == "TencentDB" { | |||||
sql = helper.StringJoin("/*slave*/ ", withSql, " select ") | |||||
} else { | |||||
sql = helper.StringJoin(withSql, "select ") | |||||
} | |||||
} | |||||
sql = helper.StringJoin(sql, title) | |||||
if this.alias != "" { | |||||
table = helper.StringJoin(table, " as ", this.alias) | |||||
} | |||||
sql = helper.StringJoin(sql, " from ", table) | |||||
if len(this.join) > 0 { | |||||
var builder strings.Builder | |||||
builder.WriteString(sql) | |||||
boo := false | |||||
for _, joinitem := range this.join { | |||||
if len(joinitem) < 2 { | |||||
continue | |||||
} | |||||
builder.WriteString(" ") | |||||
if len(joinitem) >= 3 { | |||||
builder.WriteString(joinitem[2]) | |||||
} else { | |||||
builder.WriteString("left") | |||||
} | |||||
builder.WriteString(" join ") | |||||
if withSql != "" || strings.Contains(joinitem[0], "select ") || strings.HasPrefix(joinitem[0], "(") { | |||||
builder.WriteString(joinitem[0]) | |||||
} else { | |||||
builder.WriteString(getTableName(this.dbname, joinitem[0])) | |||||
} | |||||
builder.WriteString(" on ") | |||||
builder.WriteString(joinitem[1]) | |||||
boo = true | |||||
} | |||||
if boo { | |||||
sql = builder.String() | |||||
} | |||||
} | |||||
if len(this.where) > 0 || len(this.where_or) > 0 { | |||||
sql = helper.StringJoin(sql, " where ") | |||||
} | |||||
if len(this.where) > 0 { | |||||
sql = helper.StringJoin(sql, " (", strings.Join(this.where, " and "), " ) ") | |||||
} | |||||
if len(this.where_or) > 0 { | |||||
if len(this.where) > 0 { | |||||
sql = helper.StringJoin(sql, " or ", strings.Join(this.where_or, " or ")) | |||||
} else { | |||||
sql = helper.StringJoin(sql, strings.Join(this.where_or, " or ")) | |||||
} | |||||
} | |||||
if this.groupby != "" { | |||||
sql = helper.StringJoin(sql, " group by ", this.groupby) | |||||
} | |||||
if this.having != "" { | |||||
sql = helper.StringJoin(sql, " having ", this.having) | |||||
} | |||||
if this.orderby != "" { | |||||
sql = helper.StringJoin(sql, " order by ", this.orderby) | |||||
} | |||||
if this.dbtype == "mysql" && (this.page > 0 || this.page_size > 0) { | |||||
if this.page < 1 { | |||||
this.page = 1 | |||||
} | |||||
if this.page_size < 1 { | |||||
this.page_size = 10 | |||||
} | |||||
from := strconv.Itoa((this.page - 1) * this.page_size) | |||||
offset := strconv.Itoa(this.page_size) | |||||
if from != "" && offset != "" { | |||||
sql = helper.StringJoin(sql, " limit ", from, " , ", offset) | |||||
} | |||||
} | |||||
if this.debug { | |||||
log.Println("query sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return nil, errors.New("参数错误,条件值错误") | |||||
} | |||||
return map[string]interface{}{ | |||||
"sql": sql, | |||||
"value": this.value, | |||||
}, nil | |||||
} | |||||
// 拼查询sql | |||||
func (this *Query) QueryStmt() error { | |||||
res := map[string]interface{}{} | |||||
res, err = this.BuildSelectSql() | |||||
if err != nil { | |||||
return err | |||||
} | |||||
sql := helper.ToStr(res["sql"]) | |||||
if SLAVER_DB != nil { | |||||
this.conn = SLAVER_DB | |||||
} | |||||
// else { | |||||
// this.conn = DB | |||||
// } | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼更新sql | |||||
func (this *Query) UpdateStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
if len(this.where) < 1 { | |||||
return errors.New("参数错误,缺少条件") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table, this.dbtype) | |||||
var sql string | |||||
sql = helper.StringJoin("update ", dbName, " set ", strings.Join(this.data, " , ")) | |||||
sql = helper.StringJoin(sql, " where ", strings.Join(this.where, " and ")) | |||||
if this.debug { | |||||
log.Println("update sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼批量存在更新不存在插入sql | |||||
func (this *Query) UpdateAllStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
var dataSql []string //一组用到的占位字符 | |||||
var valSql []string //占位字符组 | |||||
var updSql []string //更新字段的sql | |||||
var updFieldLen = len(this.upd_field) //需要更新的字段数量,为0时更新除id外添加值 | |||||
dataLen := len(this.save_data) | |||||
if dataLen > 0 { | |||||
//批量操作 | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
var dataSqlText string //占位字符组 | |||||
for i := 0; i < dataLen; i++ { | |||||
if i == 0 { | |||||
//第一组时分配变量空间 | |||||
fieldLen := len(this.save_data[i]) | |||||
this.data = make([]string, 0, fieldLen) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
this.value = make([]interface{}, 0, fieldLen*dataLen) | |||||
valSql = make([]string, 0, dataLen) | |||||
switch updFieldLen { | |||||
case 0: | |||||
//预览创建数据的长度 | |||||
updSql = make([]string, 0, fieldLen) | |||||
default: | |||||
//按照需要更新字段数长度 | |||||
updSql = make([]string, 0, updFieldLen) | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") //存储需要更新的字段 | |||||
} | |||||
} | |||||
for k := range this.save_data[i] { | |||||
this.data = append(this.data, k) //存储添加的字段 | |||||
dataSql = append(dataSql, "?") //存储需要的占位符 | |||||
if updFieldLen == 0 && k != "id" { | |||||
updSql = append(updSql, k+"=values("+k+")") //存储需要更新的字段 | |||||
} | |||||
} | |||||
dataSqlText = strings.Join(dataSql, ",") //组成每组占位字符格式 | |||||
} | |||||
for j := 0; j < len(this.data); j++ { | |||||
this.value = append(this.value, this.save_data[i][this.data[j]]) //存储值 | |||||
} | |||||
valSql = append(valSql, "("+dataSqlText+")") //组成占位字符组 | |||||
} | |||||
} else { | |||||
//添加一条(原理同上) | |||||
fieldLen := len(this.data) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
valSql = make([]string, 0, 1) | |||||
switch updFieldLen { | |||||
case 0: | |||||
updSql = make([]string, 0, fieldLen) | |||||
default: | |||||
updSql = make([]string, 0, updFieldLen) | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") | |||||
} | |||||
} | |||||
for i := 0; i < fieldLen; i++ { | |||||
dataSql = append(dataSql, "?") | |||||
if updFieldLen == 0 && this.data[i] != "id" { | |||||
updSql = append(updSql, this.data[i]+"=values("+this.data[i]+")") | |||||
} | |||||
} | |||||
if updFieldLen > 0 { | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") | |||||
} | |||||
} | |||||
valSql = append(valSql, "("+strings.Join(dataSql, " , ")+")") | |||||
} | |||||
if len(this.data) == 0 { | |||||
return errors.New("参数错误,没有字段值") | |||||
} | |||||
if len(this.value) == 0 { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
setText := " values " | |||||
if len(valSql) > 1 { | |||||
setText = " value " | |||||
} | |||||
sql = helper.StringJoin("insert into ", dbName, " (", strings.Join(this.data, " , "), ")", setText, strings.Join(valSql, ","), " ON DUPLICATE KEY UPDATE ", strings.Join(updSql, " , ")) | |||||
if this.debug { | |||||
log.Println("insert on duplicate key update sql:", sql, this.value) | |||||
} | |||||
conditionLen := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
conditionLen++ | |||||
} | |||||
} | |||||
if conditionLen != len(this.value) { | |||||
return errors.New("参数错误,条件值数量不匹配") | |||||
} | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼批量插入sql | |||||
func (this *Query) CreateAllStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
var dataSql []string //一组用到的占位字符 | |||||
var valSql []string //占位字符组 | |||||
dataLen := len(this.save_data) | |||||
if dataLen > 0 { | |||||
//清空字段和值 | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
var dataSqlText string //占位字符组 | |||||
for i := 0; i < dataLen; i++ { | |||||
if i == 0 { | |||||
//第一组时分配变量空间 | |||||
fieldLen := len(this.save_data[i]) | |||||
this.data = make([]string, 0, fieldLen) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
this.value = make([]interface{}, 0, fieldLen*dataLen) | |||||
valSql = make([]string, 0, dataLen) | |||||
for k := range this.save_data[i] { | |||||
this.data = append(this.data, k) //存储字段 | |||||
dataSql = append(dataSql, "?") //存储需要的占位符 | |||||
} | |||||
dataSqlText = strings.Join(dataSql, ",") //组成每组占位字符格式 | |||||
} | |||||
for j := 0; j < len(this.data); j++ { | |||||
this.value = append(this.value, this.save_data[i][this.data[j]]) //存储值 | |||||
} | |||||
valSql = append(valSql, "("+dataSqlText+")") //组成占位字符组 | |||||
} | |||||
} else { | |||||
//添加一条(原理同上) | |||||
fieldLen := len(this.data) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
for i := 0; i < fieldLen; i++ { | |||||
dataSql = append(dataSql, "?") | |||||
} | |||||
valSql = make([]string, 0, 1) | |||||
valSql = append(valSql, "("+strings.Join(dataSql, " , ")+")") | |||||
} | |||||
if len(this.data) == 0 { | |||||
return errors.New("参数错误,字段名错误") | |||||
} | |||||
if len(this.value) == 0 { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
//通过sql关键字优化批量操作和单个操作效率 | |||||
setText := " values " | |||||
if len(valSql) > 1 { | |||||
setText = " value " | |||||
} | |||||
sql = helper.StringJoin("insert into ", dbName, " (", strings.Join(this.data, " , "), ")", setText, strings.Join(valSql, ",")) | |||||
if this.debug { | |||||
log.Println("insert sql:", sql, this.value) | |||||
} | |||||
conditionLen := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
conditionLen++ | |||||
} | |||||
} | |||||
if conditionLen != len(this.value) { | |||||
return errors.New("参数错误,条件值数量不匹配") | |||||
} | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼插入sql | |||||
func (this *Query) CreateStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table, this.dbtype) | |||||
var sql string | |||||
sql = helper.StringJoin("insert into ", dbName, " set ", strings.Join(this.data, " , ")) | |||||
if this.debug { | |||||
log.Println("insert sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼删除sql | |||||
func (this *Query) DeleteStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
if len(this.where) < 1 { | |||||
return errors.New("参数错误,缺少条件") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table, this.dbtype) | |||||
var sql string | |||||
sql = helper.StringJoin("delete from ", dbName, " where ", strings.Join(this.where, " and ")) | |||||
if this.page_size > 0 { | |||||
sql = helper.StringJoin(sql, " limit ", strconv.Itoa(this.page_size)) | |||||
} | |||||
if this.debug { | |||||
log.Println("delete sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
if this.conn == nil { | |||||
this.conn = DB | |||||
} | |||||
stmt, err = this.conn.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
/** | |||||
* 执行查询列表 | |||||
* return list error | |||||
*/ | |||||
func (this *Query) Select() ([]map[string]string, error) { | |||||
_, rows, err := FetchRows(this.dbname, this.table, this.alias, this.title, this.with, this.join, | |||||
this.where, this.where_or, this.value, this.orderby, this.groupby, this.having, this.page, this.page_size, this.debug) | |||||
return rows, err | |||||
} | |||||
/** | |||||
* 执行查询多条数据 | |||||
* return row error | |||||
* 2022/01/05 | |||||
*/ | |||||
func (this *Query) List() ([]map[string]string, error) { | |||||
err := this.QueryStmt() | |||||
if err != nil { | |||||
return []map[string]string{}, err | |||||
} | |||||
if this.stmt == nil { | |||||
return []map[string]string{}, errors.New("缺少必要参数") | |||||
} | |||||
return StmtForQueryList(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行查询一条数据 | |||||
* return row error | |||||
*/ | |||||
func (this *Query) Find() (map[string]string, error) { | |||||
_, row, err := GetRow(this.dbname, this.table, this.alias, this.title, this.with, this.join, | |||||
this.where, this.where_or, this.value, this.orderby, this.groupby, this.having, this.debug) | |||||
return row, err | |||||
} | |||||
/** | |||||
* 执行查询一条数据 | |||||
* return row error | |||||
* 2022/01/05 | |||||
*/ | |||||
func (this *Query) Get() (map[string]string, error) { | |||||
this.page = 1 | |||||
this.page_size = 1 | |||||
err := this.QueryStmt() | |||||
if err != nil { | |||||
return map[string]string{}, err | |||||
} | |||||
if this.stmt == nil { | |||||
return nil, errors.New("缺少必要参数") | |||||
} | |||||
return StmtForQueryRow(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行更新 | |||||
* return is_updated error | |||||
*/ | |||||
func (this *Query) Update() (int64, error) { | |||||
err := this.UpdateStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
// 批量更新 | |||||
func (this *Query) UpdateAll() (int64, error) { | |||||
err := this.UpdateAllStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行删除 | |||||
* return is_delete error | |||||
*/ | |||||
func (this *Query) Delete() (int64, error) { | |||||
err := this.DeleteStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行写入 | |||||
* return is_insert error | |||||
*/ | |||||
func (this *Query) Create() (int64, error) { | |||||
err := this.CreateStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForInsertExec(this.stmt, this.value) | |||||
} | |||||
func (this *Query) CreateAll() (int64, error) { | |||||
err := this.CreateAllStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForInsertExec(this.stmt, this.value) | |||||
} |
@ -0,0 +1,17 @@ | |||||
package dbquery | |||||
import ( | |||||
"testing" | |||||
) | |||||
func Test_Chain(t *testing.T) { | |||||
Connect("127.0.0.1", "root", "123456", "shop", "3306") | |||||
ret, err := new(Query).Db("shop").Table("ttl_order_product").Alias("op"). | |||||
Join([]string{"ttl_product as p", "op.product_id=p.id"}). | |||||
Title("op.id,op.order_price,p.thumb").WhereOr("op.id =?").WhereOr("op.id = ?").Value(63).Value(64).Debug(true).List() | |||||
t.Log(len(ret)) | |||||
t.Log(ret) | |||||
t.Log(err) | |||||
} |
@ -1,11 +1,51 @@ | |||||
package dbquery | package dbquery | ||||
import ( | import ( | ||||
"log" | |||||
"testing" | "testing" | ||||
) | ) | ||||
func Test_GetTotal(t *testing.T) { | |||||
Connect() | |||||
total := GetTotal("dev_tetel_net", TABLE_CONFIG, "id") | |||||
t.Log(total) | |||||
func Test_Connet(t *testing.T) { | |||||
//go func() { | |||||
for i := 0; i < 1; i++ { | |||||
dbhost := "localhost" | |||||
dbname := "shop" | |||||
dbusername := "tetele" | |||||
dbpassword := "fly123456" | |||||
dbport := "3306" | |||||
table := "ttl_order_product" | |||||
err := Connect(dbhost, dbusername, dbpassword, dbname, dbport) | |||||
if err != nil { | |||||
log.Println(err.Error()) | |||||
} | |||||
//_,err = new(Query).Db(dbname).Table("ttl_user").Where("id > 0").Select() | |||||
// _, err = new(Query).Db(dbname).Table("ttl_news"). | |||||
// Datas([]string{"title=?", "content=?"}). | |||||
// Values([]interface{}{"aaaaaaaaa", "bbbbbb"}).Create() | |||||
title := "op.id,op.sn,op.order_price" | |||||
alias := "op" | |||||
join := [][]string{} | |||||
join = append(join, []string{"ttl_product as p", "op.product_id=p.id"}) | |||||
where := []string{} | |||||
where_or := []string{} | |||||
valueList := []interface{}{} | |||||
orderby := "id desc" | |||||
debug := true | |||||
// count, row, err := GetRow(dbname, table, alias, title, join, where, where_or, valueList, orderby, debug) | |||||
count, row, err := FetchRows(dbname, table, alias, title, join, where, where_or, valueList, orderby, "", 1, 10, debug) | |||||
log.Println(count) | |||||
log.Println(row) | |||||
log.Println(err) | |||||
if err != nil { | |||||
log.Println(err.Error()) | |||||
} | |||||
} | |||||
//}() | |||||
} | } |
@ -0,0 +1,9 @@ | |||||
module git.tetele.net/tgo/dbquery | |||||
go 1.14 | |||||
require ( | |||||
git.tetele.net/tgo/helper v0.1.0 | |||||
github.com/denisenkom/go-mssqldb v0.11.0 | |||||
github.com/go-sql-driver/mysql v1.5.0 | |||||
) |
@ -0,0 +1,11 @@ | |||||
git.tetele.net/tgo/helper v0.1.0 h1:ZdsBXUWX3+22ZzHTZRldBfBsQwu+CwUH8qScUvpgimE= | |||||
git.tetele.net/tgo/helper v0.1.0/go.mod h1:shYQE/hvMy3fOE8JXKGxvywOXiz3M5Nw4e+u7HR8+NY= | |||||
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI= | |||||
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | |||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= | |||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | |||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= | |||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= | |||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= | |||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
@ -0,0 +1,70 @@ | |||||
package dbquery | |||||
import ( | |||||
"database/sql" | |||||
"errors" | |||||
"fmt" | |||||
"strconv" | |||||
"log" | |||||
"time" | |||||
_ "github.com/denisenkom/go-mssqldb" | |||||
) | |||||
var MSDB_CONN *sql.DB | |||||
func MSConnect(DBHOST, DBUSER, DBPWD, DBNAME, DBPORT, encrypt string, conns ...int) error { | |||||
log.Println("msdb connectting...") | |||||
var dbConnErr error | |||||
if DBHOST != "" && DBUSER != "" && DBPWD != "" && DBPORT != "" { //&& DBNAME != "" | |||||
for i := 0; i < 10; i++ { | |||||
//连接字符串 | |||||
db_port, _ := strconv.Atoi(DBPORT) | |||||
params := "server=%s;port=%d;database=%s;user id=%s;password=%s" | |||||
if encrypt != "" { | |||||
params = params + ";encrypt=" + encrypt | |||||
} | |||||
connString := fmt.Sprintf(params, DBHOST, db_port, DBNAME, DBUSER, DBPWD) | |||||
log.Println(connString) | |||||
//建立连接 | |||||
MSDB_CONN, dbConnErr = sql.Open("mssql", connString) | |||||
if dbConnErr != nil { | |||||
log.Println("ERROR", "can not connect to Database, ", dbConnErr) | |||||
time.Sleep(time.Second * 5) | |||||
} else { | |||||
err = MSDB_CONN.Ping() | |||||
log.Println("msdb connected", err) | |||||
break | |||||
} | |||||
} | |||||
} else { | |||||
return errors.New("msdb connection params errors") | |||||
} | |||||
return dbConnErr | |||||
} | |||||
func CloseMSConn() error { | |||||
if MSDB_CONN != nil { | |||||
return MSDB_CONN.Close() | |||||
} | |||||
return nil | |||||
} |
@ -0,0 +1,892 @@ | |||||
package dbquery | |||||
/** | |||||
* 事务操作 | |||||
*/ | |||||
import ( | |||||
"database/sql" | |||||
"errors" | |||||
"log" | |||||
"strconv" | |||||
"strings" | |||||
"git.tetele.net/tgo/helper" | |||||
) | |||||
type TxQuery struct { | |||||
dbname string | |||||
table string | |||||
alias string | |||||
title string | |||||
where []string | |||||
where_or []string | |||||
join [][]string //[["tablea as a","a.id=b.id","left"]] | |||||
data []string | |||||
value []interface{} | |||||
save_data []map[string]interface{} //批量操作的数据[["title":"a","num":1,],["title":"a","num":1,]] | |||||
upd_field []string // 批量更新时需要更新的字段,为空时按除id外的字段进行更新 | |||||
orderby string | |||||
groupby string | |||||
having string | |||||
page int | |||||
page_size int | |||||
stmt *sql.Stmt | |||||
conn *sql.DB | |||||
tx *sql.Tx | |||||
debug bool | |||||
with [][]string //[[临时表的sql语句,临时表的名称]] | |||||
} | |||||
func NewTxQuery(t ...string) *TxQuery { | |||||
var conn_type *sql.DB = DB | |||||
if len(t) > 0 { | |||||
switch t[0] { | |||||
case "mysql": | |||||
conn_type = DB | |||||
case "mssql": //sql server | |||||
conn_type = MSDB_CONN | |||||
} | |||||
} | |||||
tx, err := conn_type.Begin() | |||||
if err != nil { | |||||
log.Println("start tx begin error", err) | |||||
} | |||||
return &TxQuery{ | |||||
conn: conn_type, | |||||
tx: tx, | |||||
} | |||||
} | |||||
func (this *TxQuery) Conn(conn *sql.DB) *TxQuery { | |||||
this.conn = conn | |||||
return this | |||||
} | |||||
func (this *TxQuery) Db(dbname string) *TxQuery { | |||||
this.dbname = dbname | |||||
return this | |||||
} | |||||
func (this *TxQuery) Table(tablename string) *TxQuery { | |||||
this.table = tablename | |||||
return this | |||||
} | |||||
func (this *TxQuery) Alias(tablename string) *TxQuery { | |||||
this.alias = tablename | |||||
return this | |||||
} | |||||
func (this *TxQuery) Title(title string) *TxQuery { | |||||
this.title = title | |||||
return this | |||||
} | |||||
func (this *TxQuery) Page(page int) *TxQuery { | |||||
this.page = page | |||||
return this | |||||
} | |||||
func (this *TxQuery) PageSize(page_num int) *TxQuery { | |||||
this.page_size = page_num | |||||
return this | |||||
} | |||||
func (this *TxQuery) Orderby(orderby string) *TxQuery { | |||||
this.orderby = orderby | |||||
return this | |||||
} | |||||
func (this *TxQuery) Groupby(groupby string) *TxQuery { | |||||
this.groupby = groupby | |||||
return this | |||||
} | |||||
func (this *TxQuery) Having(having string) *TxQuery { | |||||
this.having = having | |||||
return this | |||||
} | |||||
func (this *TxQuery) Where(where string) *TxQuery { | |||||
this.where = append(this.where, where) | |||||
return this | |||||
} | |||||
func (this *TxQuery) With(with []string) *TxQuery { | |||||
this.with = append(this.with, with) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Withs(withs [][]string) *TxQuery { | |||||
this.with = append(this.with, withs...) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Wheres(wheres []string) *TxQuery { | |||||
if len(wheres) > 0 { | |||||
this.where = append(this.where, wheres...) | |||||
} | |||||
return this | |||||
} | |||||
func (this *TxQuery) WhereOr(where string) *TxQuery { | |||||
this.where_or = append(this.where_or, where) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Value(value interface{}) *TxQuery { | |||||
this.value = append(this.value, value) | |||||
return this | |||||
} | |||||
func (this *TxQuery) SaveData(value map[string]interface{}) *TxQuery { | |||||
this.save_data = append(this.save_data, value) | |||||
return this | |||||
} | |||||
func (this *TxQuery) SaveDatas(value []map[string]interface{}) *TxQuery { | |||||
this.save_data = append(this.save_data, value...) | |||||
return this | |||||
} | |||||
func (this *TxQuery) UpdField(value string) *TxQuery { | |||||
this.upd_field = append(this.upd_field, value) | |||||
return this | |||||
} | |||||
func (this *TxQuery) UpdFields(value []string) *TxQuery { | |||||
this.upd_field = append(this.upd_field, value...) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Values(values []interface{}) *TxQuery { | |||||
this.value = append(this.value, values...) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Join(join []string) *TxQuery { | |||||
this.join = append(this.join, join) | |||||
return this | |||||
} | |||||
/** | |||||
* 左连接 | |||||
* 2023/08/10 | |||||
* gz | |||||
*/ | |||||
func (this *TxQuery) LeftJoin(table_name string, condition string) *TxQuery { | |||||
this.join = append(this.join, []string{table_name, condition, "left"}) | |||||
return this | |||||
} | |||||
/** | |||||
* 右连接 | |||||
* 2023/08/10 | |||||
* gz | |||||
*/ | |||||
func (this *TxQuery) RightJoin(table_name string, condition string) *TxQuery { | |||||
this.join = append(this.join, []string{table_name, condition, "right"}) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Data(data string) *TxQuery { | |||||
this.data = append(this.data, data) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Datas(datas []string) *TxQuery { | |||||
this.data = append(this.data, datas...) | |||||
return this | |||||
} | |||||
func (this *TxQuery) Debug(debug bool) *TxQuery { | |||||
this.debug = debug | |||||
return this | |||||
} | |||||
/* | |||||
* 清理上次查询 | |||||
*/ | |||||
func (this *TxQuery) Clean() *TxQuery { | |||||
this.title = "" | |||||
this.where = this.where[0:0] | |||||
this.where_or = this.where_or[0:0] | |||||
this.join = this.join[0:0] | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
this.orderby = "" | |||||
this.groupby = "" | |||||
this.page = 0 | |||||
this.page_size = 0 | |||||
this.save_data = this.save_data[0:0] | |||||
this.upd_field = this.upd_field[0:0] | |||||
this.having = "" | |||||
this.alias = "" | |||||
this.with = this.with[0:0] | |||||
return this | |||||
} | |||||
// 返回表名 | |||||
func (this *TxQuery) GetTableName(table string) string { | |||||
return getTableName(this.dbname, table) | |||||
} | |||||
// 构造子查询 | |||||
func (this *TxQuery) BuildSelectSql() (map[string]interface{}, error) { | |||||
if this.dbname == "" && this.table == "" { | |||||
return nil, errors.New("参数错误,没有数据表") | |||||
} | |||||
var table = "" | |||||
withSql := "" | |||||
if len(this.with) > 0 { | |||||
var builder strings.Builder | |||||
builder.WriteString("WITH ") | |||||
boo := false | |||||
for k, v := range this.with { | |||||
if len(v) < 2 { | |||||
continue | |||||
} | |||||
if k != 0 { | |||||
builder.WriteString(", ") | |||||
} | |||||
builder.WriteString(v[1]) | |||||
builder.WriteString(" as (") | |||||
builder.WriteString(v[0]) | |||||
builder.WriteString(")") | |||||
boo = true | |||||
} | |||||
if boo { | |||||
builder.WriteString(" ") | |||||
withSql = builder.String() | |||||
} | |||||
} | |||||
if withSql != "" || strings.Contains(this.table, "select ") || strings.HasPrefix(this.table, "(") { | |||||
table = this.table | |||||
} else { | |||||
table = getTableName(this.dbname, this.table) | |||||
} | |||||
var sql, title string | |||||
if this.title != "" { | |||||
title = this.title | |||||
} else { | |||||
title = "*" | |||||
} | |||||
sql = helper.StringJoin(withSql, "select ", title) | |||||
if this.alias != "" { | |||||
table = helper.StringJoin(table, " as ", this.alias) | |||||
} | |||||
sql = helper.StringJoin(sql, " from ", table) | |||||
if len(this.join) > 0 { | |||||
var builder strings.Builder | |||||
builder.WriteString(sql) | |||||
boo := false | |||||
for _, joinitem := range this.join { | |||||
if len(joinitem) < 2 { | |||||
continue | |||||
} | |||||
builder.WriteString(" ") | |||||
if len(joinitem) >= 3 { | |||||
builder.WriteString(joinitem[2]) | |||||
} else { | |||||
builder.WriteString("left") | |||||
} | |||||
builder.WriteString(" join ") | |||||
if withSql != "" || strings.Contains(joinitem[0], "select ") || strings.HasPrefix(joinitem[0], "(") { | |||||
builder.WriteString(joinitem[0]) | |||||
} else { | |||||
builder.WriteString(getTableName(this.dbname, joinitem[0])) | |||||
} | |||||
builder.WriteString(" on ") | |||||
builder.WriteString(joinitem[1]) | |||||
boo = true | |||||
} | |||||
if boo { | |||||
sql = builder.String() | |||||
} | |||||
} | |||||
if len(this.where) > 0 || len(this.where_or) > 0 { | |||||
sql = helper.StringJoin(sql, " where ") | |||||
} | |||||
if len(this.where) > 0 { | |||||
sql = helper.StringJoin(sql, " (", strings.Join(this.where, " and "), " ) ") | |||||
} | |||||
if len(this.where_or) > 0 { | |||||
if len(this.where) > 0 { | |||||
sql = helper.StringJoin(sql, " or ", strings.Join(this.where_or, " or ")) | |||||
} else { | |||||
sql = helper.StringJoin(sql, strings.Join(this.where_or, " or ")) | |||||
} | |||||
} | |||||
if this.groupby != "" { | |||||
sql = helper.StringJoin(sql, " group by ", this.groupby) | |||||
} | |||||
if this.having != "" { | |||||
sql = helper.StringJoin(sql, " having ", this.having) | |||||
} | |||||
if this.orderby != "" { | |||||
sql = helper.StringJoin(sql, " order by ", this.orderby) | |||||
} | |||||
if this.page > 0 || this.page_size > 0 { | |||||
if this.page < 1 { | |||||
this.page = 1 | |||||
} | |||||
if this.page_size < 1 { | |||||
this.page_size = 10 | |||||
} | |||||
from := strconv.Itoa((this.page - 1) * this.page_size) | |||||
offset := strconv.Itoa(this.page_size) | |||||
if from != "" && offset != "" { | |||||
sql = helper.StringJoin(sql, " limit ", from, " , ", offset) | |||||
} | |||||
} | |||||
if this.debug { | |||||
log.Println("query sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return nil, errors.New("参数错误,条件值错误") | |||||
} | |||||
return map[string]interface{}{ | |||||
"sql": sql, | |||||
"value": this.value, | |||||
}, nil | |||||
} | |||||
// 获取表格信息 | |||||
func (this *TxQuery) GetTableInfo(table string) (map[string]interface{}, error) { | |||||
field := []string{ | |||||
"COLUMN_NAME", //字段名 | |||||
"COLUMN_DEFAULT", //默认值 | |||||
"DATA_TYPE", //数据类型 | |||||
"COLUMN_TYPE", //数据类型+长度 | |||||
"COLUMN_COMMENT", //备注 | |||||
"IS_NULLABLE", //是否为空 | |||||
} | |||||
sql := "select `" + strings.Join(field, "`,`") + "` from information_schema.COLUMNS where table_name = ? and table_schema = ?" | |||||
stmtSql, err := this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
list, err := StmtForQueryList(stmtSql, []interface{}{table, this.dbname}) | |||||
if err != nil { | |||||
return nil, err | |||||
} | |||||
rows := make([]interface{}, 0, len(list)) | |||||
fieldName := make([]string, 0, len(list)) | |||||
for _, item := range list { | |||||
info := map[string]interface{}{ | |||||
"name": "", | |||||
"column_type": "", | |||||
"is_null": true, | |||||
"data_type": "", | |||||
"comment": "", | |||||
"default": "", | |||||
} | |||||
for _, k := range field { | |||||
index := helper.StrFirstToUpper(k) | |||||
if v, ok := item[index]; ok { | |||||
switch k { | |||||
case "COLUMN_NAME": | |||||
info["name"] = v | |||||
case "COLUMN_DEFAULT": | |||||
info["default"] = v | |||||
case "DATA_TYPE": | |||||
info["data_type"] = v | |||||
case "COLUMN_TYPE": | |||||
info["column_type"] = helper.ToInt64(v) | |||||
case "COLUMN_COMMENT": | |||||
info["comment"] = helper.ToInt64(v) | |||||
case "IS_NULLABLE": | |||||
if v == "NO" { | |||||
info["is_null"] = false | |||||
} | |||||
} | |||||
} | |||||
} | |||||
name := helper.ToStr(info["name"]) | |||||
if name != "" { | |||||
rows = append(rows, info) | |||||
fieldName = append(fieldName, name) | |||||
} | |||||
} | |||||
return map[string]interface{}{ | |||||
"field": fieldName, | |||||
"list": rows, | |||||
}, nil | |||||
} | |||||
// 拼查询sql | |||||
func (this *TxQuery) QueryStmt() error { | |||||
res := map[string]interface{}{} | |||||
res, err = this.BuildSelectSql() | |||||
if err != nil { | |||||
return err | |||||
} | |||||
sql := helper.ToStr(res["sql"]) | |||||
stmt, err = this.tx.Prepare(sql + " FOR UPDATE") | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼更新sql | |||||
func (this *TxQuery) UpdateStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
if len(this.where) < 1 { | |||||
return errors.New("参数错误,缺少条件") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
sql = helper.StringJoin("update ", dbName, " set ", strings.Join(this.data, " , ")) | |||||
sql = helper.StringJoin(sql, " where ", strings.Join(this.where, " and ")) | |||||
if this.debug { | |||||
log.Println("update sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
stmt, err = this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼批量存在更新不存在插入sql | |||||
func (this *TxQuery) UpdateAllStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
var dataSql []string //一组用到的占位字符 | |||||
var valSql []string //占位字符组 | |||||
var updSql []string //更新字段的sql | |||||
var updFieldLen = len(this.upd_field) //需要更新的字段数量,为0时更新除id外添加值 | |||||
dataLen := len(this.save_data) | |||||
if dataLen > 0 { | |||||
//批量操作 | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
var dataSqlText string //占位字符组 | |||||
for i := 0; i < dataLen; i++ { | |||||
if i == 0 { | |||||
//第一组时分配变量空间 | |||||
fieldLen := len(this.save_data[i]) | |||||
this.data = make([]string, 0, fieldLen) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
this.value = make([]interface{}, 0, fieldLen*dataLen) | |||||
valSql = make([]string, 0, dataLen) | |||||
switch updFieldLen { | |||||
case 0: | |||||
//预览创建数据的长度 | |||||
updSql = make([]string, 0, fieldLen) | |||||
default: | |||||
//按照需要更新字段数长度 | |||||
updSql = make([]string, 0, updFieldLen) | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") //存储需要更新的字段 | |||||
} | |||||
} | |||||
for k := range this.save_data[i] { | |||||
this.data = append(this.data, k) //存储添加的字段 | |||||
dataSql = append(dataSql, "?") //存储需要的占位符 | |||||
if updFieldLen == 0 && k != "id" { | |||||
updSql = append(updSql, k+"=values("+k+")") //存储需要更新的字段 | |||||
} | |||||
} | |||||
dataSqlText = strings.Join(dataSql, ",") //组成每组占位字符格式 | |||||
} | |||||
for j := 0; j < len(this.data); j++ { | |||||
this.value = append(this.value, this.save_data[i][this.data[j]]) //存储值 | |||||
} | |||||
valSql = append(valSql, "("+dataSqlText+")") //组成占位字符组 | |||||
} | |||||
} else { | |||||
//添加一条(原理同上) | |||||
fieldLen := len(this.data) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
valSql = make([]string, 0, 1) | |||||
switch updFieldLen { | |||||
case 0: | |||||
updSql = make([]string, 0, fieldLen) | |||||
default: | |||||
updSql = make([]string, 0, updFieldLen) | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") | |||||
} | |||||
} | |||||
for i := 0; i < fieldLen; i++ { | |||||
dataSql = append(dataSql, "?") | |||||
if updFieldLen == 0 && this.data[i] != "id" { | |||||
updSql = append(updSql, this.data[i]+"=values("+this.data[i]+")") | |||||
} | |||||
} | |||||
if updFieldLen > 0 { | |||||
for _, k := range this.upd_field { | |||||
updSql = append(updSql, k+"=values("+k+")") | |||||
} | |||||
} | |||||
valSql = append(valSql, "("+strings.Join(dataSql, " , ")+")") | |||||
} | |||||
if len(this.data) == 0 { | |||||
return errors.New("参数错误,没有字段值") | |||||
} | |||||
if len(this.value) == 0 { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
setText := " values " | |||||
if len(valSql) > 1 { | |||||
setText = " value " | |||||
} | |||||
sql = helper.StringJoin("insert into ", dbName, " (", strings.Join(this.data, " , "), ")", setText, strings.Join(valSql, ","), " ON DUPLICATE KEY UPDATE ", strings.Join(updSql, " , ")) | |||||
if this.debug { | |||||
log.Println("insert on duplicate key update sql:", sql, this.value) | |||||
} | |||||
conditionLen := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
conditionLen++ | |||||
} | |||||
} | |||||
if conditionLen != len(this.value) { | |||||
return errors.New("参数错误,条件值数量不匹配") | |||||
} | |||||
stmt, err = this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼插入sql | |||||
func (this *TxQuery) CreateStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
sql = helper.StringJoin("insert into ", dbName, " set ", strings.Join(this.data, " , ")) | |||||
if this.debug { | |||||
log.Println("insert sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
stmt, err = this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼批量插入sql | |||||
func (this *TxQuery) CreateAllStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
var dataSql []string //一组用到的占位字符 | |||||
var valSql []string //占位字符组 | |||||
dataLen := len(this.save_data) | |||||
if dataLen > 0 { | |||||
//清空字段和值 | |||||
this.data = this.data[0:0] | |||||
this.value = this.value[0:0] | |||||
var dataSqlText string //占位字符组 | |||||
for i := 0; i < dataLen; i++ { | |||||
if i == 0 { | |||||
//第一组时分配变量空间 | |||||
fieldLen := len(this.save_data[i]) | |||||
this.data = make([]string, 0, fieldLen) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
this.value = make([]interface{}, 0, fieldLen*dataLen) | |||||
valSql = make([]string, 0, dataLen) | |||||
for k := range this.save_data[i] { | |||||
this.data = append(this.data, k) //存储字段 | |||||
dataSql = append(dataSql, "?") //存储需要的占位符 | |||||
} | |||||
dataSqlText = strings.Join(dataSql, ",") //组成每组占位字符格式 | |||||
} | |||||
for j := 0; j < len(this.data); j++ { | |||||
this.value = append(this.value, this.save_data[i][this.data[j]]) //存储值 | |||||
} | |||||
valSql = append(valSql, "("+dataSqlText+")") //组成占位字符组 | |||||
} | |||||
} else { | |||||
//添加一条(原理同上) | |||||
fieldLen := len(this.data) | |||||
dataSql = make([]string, 0, fieldLen) | |||||
for i := 0; i < fieldLen; i++ { | |||||
dataSql = append(dataSql, "?") | |||||
} | |||||
valSql = make([]string, 0, 1) | |||||
valSql = append(valSql, "("+strings.Join(dataSql, " , ")+")") | |||||
} | |||||
if len(this.data) == 0 { | |||||
return errors.New("参数错误,字段名错误") | |||||
} | |||||
if len(this.value) == 0 { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
//通过sql关键字优化批量操作和单个操作效率 | |||||
setText := " values " | |||||
if len(valSql) > 1 { | |||||
setText = " value " | |||||
} | |||||
sql = helper.StringJoin("insert into ", dbName, " (", strings.Join(this.data, " , "), ")", setText, strings.Join(valSql, ",")) | |||||
if len(this.value) == 0 { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
if this.debug { | |||||
log.Println("insert sql:", sql, this.value) | |||||
} | |||||
conditionLen := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
conditionLen++ | |||||
} | |||||
} | |||||
if conditionLen != len(this.value) { | |||||
return errors.New("参数错误,条件值数量不匹配") | |||||
} | |||||
stmt, err = this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
// 拼删除sql | |||||
func (this *TxQuery) DeleteStmt() error { | |||||
if this.dbname == "" && this.table == "" { | |||||
return errors.New("参数错误,没有数据表") | |||||
} | |||||
if len(this.where) < 1 { | |||||
return errors.New("参数错误,缺少条件") | |||||
} | |||||
dbName := getTableName(this.dbname, this.table) | |||||
var sql string | |||||
sql = helper.StringJoin("delete from ", dbName, " where ", strings.Join(this.where, " and ")) | |||||
if this.page_size > 0 { | |||||
sql = helper.StringJoin(sql, " limit ", strconv.Itoa(this.page_size)) | |||||
} | |||||
if this.debug { | |||||
log.Println("delete sql:", sql, this.value) | |||||
} | |||||
condition_len := 0 //所有条件数 | |||||
for _, ch2 := range sql { | |||||
if string(ch2) == "?" { | |||||
condition_len++ | |||||
} | |||||
} | |||||
if condition_len != len(this.value) { | |||||
return errors.New("参数错误,条件值错误") | |||||
} | |||||
stmt, err = this.tx.Prepare(sql) | |||||
if err != nil { | |||||
return err | |||||
} | |||||
this.stmt = stmt | |||||
return nil | |||||
} | |||||
/** | |||||
* 执行查询列表 | |||||
* return list error | |||||
*/ | |||||
func (this *TxQuery) Select() ([]map[string]string, error) { | |||||
err := this.QueryStmt() | |||||
if err != nil { | |||||
return []map[string]string{}, err | |||||
} | |||||
if this.stmt == nil { | |||||
return []map[string]string{}, errors.New("缺少必要参数") | |||||
} | |||||
return StmtForQueryList(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行查询一条数据 | |||||
* return row error | |||||
*/ | |||||
func (this *TxQuery) Find() (map[string]string, error) { | |||||
this.page = 1 | |||||
this.page_size = 1 | |||||
err := this.QueryStmt() | |||||
if err != nil { | |||||
return map[string]string{}, err | |||||
} | |||||
if this.stmt == nil { | |||||
return nil, errors.New("缺少必要参数") | |||||
} | |||||
return StmtForQueryRow(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行更新 | |||||
* return is_updated error | |||||
*/ | |||||
func (this *TxQuery) Update() (int64, error) { | |||||
err := this.UpdateStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
// UpdateAll 批量更新(根据唯一键判断存在则更新,不存在则创建) | |||||
func (this *TxQuery) UpdateAll() (int64, error) { | |||||
err := this.UpdateAllStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行删除 | |||||
* return is_delete error | |||||
*/ | |||||
func (this *TxQuery) Delete() (int64, error) { | |||||
err := this.DeleteStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForUpdateExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行写入 | |||||
* return is_insert error | |||||
*/ | |||||
func (this *TxQuery) Create() (int64, error) { | |||||
err := this.CreateStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForInsertExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 执行批量写入 | |||||
* return is_insert error | |||||
*/ | |||||
func (this *TxQuery) CreateAll() (int64, error) { | |||||
err := this.CreateAllStmt() | |||||
if err != nil { | |||||
return 0, err | |||||
} | |||||
return StmtForInsertExec(this.stmt, this.value) | |||||
} | |||||
/** | |||||
* 提交 | |||||
*/ | |||||
func (this *TxQuery) Commit() error { | |||||
return this.tx.Commit() | |||||
} | |||||
/** | |||||
* 回滚 | |||||
*/ | |||||
func (this *TxQuery) Rollback() error { | |||||
return this.tx.Rollback() | |||||
} |