/* ================================================================================= * License: GPL-2.0 license * Author: 众产® https://ciy.cn/code * Version: 0.1.0 ================================================================================= SQL连接器 CiySQL / NewCiySQL ================================================================================= csql := c.NewCiySQL("table") //支持 table a 别名 csql.Where(field, any...) //查询条件,支持多个?。默认and,可拼接or条件 csql.Where_daterange(field, data) //绝对日期区间查询。2022-1-1~2022-2-1 (只日期) 2022-1-1 0:0:0~2022-1-1 8:0:0(带时间) csql.Where_dayrange(field, data) //相对日期区间查询。-30~0 (最近1个月) 0(今天) -1(昨天) csql.Where_monthrange(field, data) //月份区间查询。 2024-1 (本月) 2024-1~2024-2 (月份区间) csql.Where_numrange(field,data1,data2,bet) //数字区间查询。 支持普通数字(bet1)、钱(bet=100)、公斤(bet=1000)等 csql.Order(order) //排序 csql.Limit(pageno, pagecount) //分页,第n页,每页n条 csql.Column(col) //查询字段,默认* 支持!xxx,xxx 排除字段 csql.Group(order) //分组 csql.Having(order) //分组条件 csql.Join(table, onsql,op) //Join关联 op默认left,可填right/inner/outer csql.RawSQL(sql, any...) //原始SQL语句 ================================================================================= 示例: csql := c.NewCiySQL("user") csql.Where("name like", "王") csql.Order("id desc") csql.Limit(1, 10) ================================================================================= */ package zciyon import ( "fmt" "regexp" "strings" "time" ) type CiySQL struct { tsmt []any //预编译数据 rawsql string //原始SQL table string //表名 sqlcolumn string //字段名 sqllimit string //限制条数 sqlwhere string //条件 sqlorder string //排序 sqlgroup string //分组 sqlhaving string //分组条件 sqljoin string //连接 Err string //错误信息 LastSQL string //最后一条执行的SQL语句 } func NewCiySQL(table string) *CiySQL { db := &CiySQL{} db.tsmt = make([]any, 0) db.table = table return db } func (thos *CiySQL) RawSQL(sqlstr string, argdata ...any) *CiySQL { cnt := strings.Count(sqlstr, "?") if cnt > 0 { if cnt != len(argdata) { thos.Err = "_sql data length mismatch" return thos } else { thos.tsmt = argdata } } thos.rawsql = sqlstr return thos } func (thos *CiySQL) Column(col string) *CiySQL { thos.sqlcolumn = col return thos } func (thos *CiySQL) Limit(pageno int, pagecount int) *CiySQL { if pageno < 1 { pageno = 1 } if pagecount < 1 { pagecount = 10 } thos.sqllimit = fmt.Sprintf(" limit %d,%d", (pageno-1)*pagecount, pagecount) return thos } // eg. csql.Join('tab2','left','tab1.id=tab2.id'); func (thos *CiySQL) Join(table string, on string, argop ...string) *CiySQL { //op:left right inner outer op := "left" if len(argop) > 0 { op = argop[0] } thos.sqljoin = fmt.Sprintf(" %s join %s on %s", op, table, on) return thos } func (thos *CiySQL) Order(order string) *CiySQL { re := regexp.MustCompile(`^[0-9a-zA-Z_\-\.]+$`) chks := strings.Split(order, ",") for _, chk := range chks { chk = strings.Replace(chk, "desc", "", -1) chk = strings.TrimSpace(chk) if !re.MatchString(chk) { return thos } } thos.sqlorder = order return thos } func (thos *CiySQL) Group(group string) *CiySQL { thos.sqlgroup = group return thos } func (thos *CiySQL) Having(having string, argdata ...any) *CiySQL { thos.sqlhaving = thos.query(having, argdata...) return thos } func (thos *CiySQL) Where(query string, argdata ...any) *CiySQL { thos.sqlwhere = thos.sqlwhere + thos.query(query, argdata...) return thos } func (thos *CiySQL) query(query string, argdata ...any) string { if query == "" { thos.Err = "_query query empty" return "" } if len(argdata) == 0 { if query == "id" { return "id=0" // 防止误操作 } return " and " + query } cnt := strings.Count(query, "?") if cnt > 0 { if cnt != len(argdata) { thos.Err = "_query data length mismatch" return "" } if query[0] != ' ' { query = " and " + query } thos.tsmt = append(thos.tsmt, argdata...) return query } query = strings.TrimSpace(query) data := Tostr(argdata[0]) if data == "" { return "" } if strings.HasSuffix(query, " like") { if data == ",," { return "" } if !strings.HasPrefix(data, "%") && !strings.HasSuffix(data, "%") { data = "%" + data + "%" } query = fmt.Sprintf(" and %s ?", query) } else if strings.HasSuffix(query, " in") { return fmt.Sprintf(" and %s (%s)", query, data) } else { lastChar := rune(query[len(query)-1]) if lastChar != '=' && lastChar != '>' && lastChar != '<' { query += "=" } query = fmt.Sprintf(" and %s?", query) } thos.tsmt = append(thos.tsmt, data) return query } func (thos *CiySQL) Buildwhere() string { if thos.sqlwhere == "" { return "" } thos.sqlwhere = strings.TrimPrefix(thos.sqlwhere, " and ") return " where " + thos.sqlwhere } func (thos *CiySQL) Buildsql(column string) (string, string) { if thos.table == "" { return "", "" } sqlstr := fmt.Sprintf("select %s from %s", column, thos.table) if thos.sqljoin != "" { sqlstr += thos.sqljoin } sqlstr += thos.Buildwhere() if thos.sqlgroup != "" { sqlstr += " group by " + thos.sqlgroup } if thos.sqlhaving != "" { sqlstr += " having " + strings.TrimPrefix(thos.sqlhaving, " and ") } if thos.sqlorder != "" { sqlstr += " order by " + thos.sqlorder } return sqlstr, column } func (thos *CiySQL) Where_daterange(query string, data string) *CiySQL { //2022-1-1~2022-2-1 2022-1-1 0:0:0~2022-1-1 8:0:0 ds := strings.Split(data, "~") if len(ds) != 2 { return thos } dstr := strings.TrimSpace(ds[0]) if dstr != "" { if !strings.Contains(dstr, ":") { dstr = dstr + " 00:00:00" } t, err := time.ParseInLocation("2006-01-02 15:04:05", dstr, time.Local) if err == nil { thos.Where(query+">=", t.Unix()) } } dstr = strings.TrimSpace(ds[1]) if dstr != "" { if !strings.Contains(dstr, ":") { dstr = dstr + " 23:59:59" } t, err := time.ParseInLocation("2006-01-02 15:04:05", dstr, time.Local) if err == nil { thos.Where(query+"<=", t.Unix()) } } return thos } func (thos *CiySQL) Where_dayrange(query string, data string) *CiySQL { // -30~0最近1个月。 0今天。 -1昨天。 ds := strings.Split(data, "~") now := time.Now() date := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) dstr := strings.TrimSpace(ds[0]) if dstr != "" { dint := Toint(dstr) t := date.AddDate(0, 0, dint) thos.Where(query+">=", t.Unix()) } if len(ds) == 1 { dstr = strings.TrimSpace(ds[0]) } else { dstr = strings.TrimSpace(ds[1]) } if dstr != "" { dint := Toint(dstr) t := date.AddDate(0, 0, dint+1) thos.Where(query+"<=", t.Unix()) } return thos } func (thos *CiySQL) Where_monthrange(query string, data string) *CiySQL { //2024-1本月 2024-1~2024-2月份区间 ds := strings.Split(data, "~") dstr := strings.TrimSpace(ds[0]) if dstr != "" { if !strings.Contains(dstr, ":") { dstr = dstr + "-01 00:00:00" } t, err := time.ParseInLocation("2006-01-02 15:04:05", dstr, time.Local) if err == nil { thos.Where(query+">=", t.Unix()) } } if len(ds) == 1 { dstr = strings.TrimSpace(ds[0]) } else { dstr = strings.TrimSpace(ds[1]) } if dstr != "" { if !strings.Contains(dstr, ":") { dstr = dstr + "-01 23:59:59" } t, err := time.ParseInLocation("2006-01-02 15:04:05", dstr, time.Local) if err == nil { thos.Where(query+"<=", t.Unix()) } } return thos } func (thos *CiySQL) Where_numrange(query string, data1 any, data2 any, bet int) *CiySQL { dstr := strings.TrimSpace(Tostr(data1)) if dstr != "" { dnum := Tofloat(dstr) * float64(bet) thos.Where(query+">=", dnum) } dstr = strings.TrimSpace(Tostr(data2)) if dstr != "" { dnum := Tofloat(dstr) * float64(bet) thos.Where(query+"<=", dnum) } return thos }