package mqe import ( "fmt" "sort" "strconv" ) type GetYearIndexReq struct { Since int64 `json:"since"` // из фильтр-формы Until int64 `json:"until"` // из фильтр-формы LastDayOfMonth int `json:"lastDayOfMonth"` // например, конец месяца 25 число FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00 MetricIDs []int64 `json:"metricIDs"` } func (s *MeasureQueryEngine) GetYearIndex(req GetYearIndexReq) (years []int, err error) { if len(req.MetricIDs) == 0 { return } var ( lte, gte string args = []any{ req.MetricIDs, } ) if req.Since > 0 { lte = " AND tm >= ?" args = append(args, req.Since) } if req.Until > 0 { gte = " AND tm <= ?" args = append(args, req.Until) } q := fmt.Sprintf(` SELECT YEAR(FROM_UNIXTIME(tm)) as y FROM f64 WHERE metricID IN (?)%s%s GROUP BY y`, lte, gte) // fmt.Println(q) // fmt.Printf("%v\n", args) err = s.db.ListQuery(&years, q, args...) if err != nil { return } sort.Ints(years) return } type GetMonthIndexReq struct { Since int64 `json:"since"` // из фильтр-формы Until int64 `json:"until"` // из фильтр-формы LastDayOfMonth int `json:"lastDayOfMonth"` // например, конец месяца 25 число FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00 MetricIDs []int64 `json:"metricIDs"` } type YearMonth struct { Year int `json:"year"` Months []int `json:"months"` } func (s *MeasureQueryEngine) GetMonthIndex(req GetMonthIndexReq) (years []YearMonth, err error) { if len(req.MetricIDs) == 0 { return } dt, err := getDateTimeFacingFHDAndLDM(req.FirstHourOfDay, req.LastDayOfMonth) if err != nil { return } var ( lte, gte string args = []any{ req.MetricIDs, } ) if req.Since > 0 { lte = " AND tm >= ?" args = append(args, req.Since) } if req.Until > 0 { gte = " AND tm <= ?" args = append(args, req.Until) } // ВАЖНО! // Не сортируем средствами MySQL чтобы не создавать временный файл query := fmt.Sprintf(` SELECT DATE_FORMAT(%s, '%s') as p FROM f64 WHERE metricID IN (?)%s%s GROUP BY p`, dt, "%Y%m", lte, gte) var ( temp []string yms []int ) err = s.db.ListQuery(&temp, query, args...) if err != nil { return } for _, str := range temp { var ym int ym, err = strconv.Atoi(str) if err != nil { return } yms = append(yms, ym) } return IndexYms(yms), nil } type GetDayIndexReq struct { Since int64 `json:"since"` // из фильтр-формы Until int64 `json:"until"` // из фильтр-формы FirstHourOfDay int `json:"firstHourOfDay"` // например день начинается в 6:00 MetricIDs []int64 `json:"metricIDs"` } type YearMonthDay struct { Year int `json:"year"` Months []MonthDay `json:"months"` } type MonthDay struct { Month int `json:"month"` Days []int `json:"days"` } func (s *MeasureQueryEngine) GetDayIndex(req GetDayIndexReq) (years []YearMonthDay, err error) { if len(req.MetricIDs) == 0 { return } dt, err := getDateTimeFacingFHD(req.FirstHourOfDay) if err != nil { return } var ( lte, gte string args = []any{ req.MetricIDs, } ) if req.Since > 0 { lte = " AND tm >= ?" args = append(args, req.Since) } if req.Until > 0 { gte = " AND tm <= ?" args = append(args, req.Until) } // ВАЖНО! // Не сортируем средствами MySQL чтобы не создавать временный файл query := fmt.Sprintf(` SELECT DATE_FORMAT(%s, '%s') as p FROM f64 WHERE metricID IN(?)%s%s GROUP BY p`, dt, "%Y%m%d", lte, gte) //fmt.Printf("%s\n", query) var ( temp []string ymds []int ) err = s.db.ListQuery(&temp, query, args...) if err != nil { return } //pretty.PPrintln("temp", temp) for _, str := range temp { var ymd int ymd, err = strconv.Atoi(str) if err != nil { return } ymds = append(ymds, ymd) } return IndexYmds(ymds), nil } func IndexYmds(ymds []int) (years []YearMonthDay) { if len(ymds) == 0 { return } sort.Ints(ymds) var ( months []MonthDay days []int year, month, day int ) for _, ymd := range ymds { y := ymd / 10000 m := (ymd % 10000) / 100 d := ymd % 100 if year == 0 { // инициализация year = y month = m day = d } else { if y != year { days = append(days, day) months = append(months, MonthDay{ Month: month, Days: days, }) years = append(years, YearMonthDay{ Year: year, Months: months, }) year = y month = m day = d months = nil days = nil } else if m != month { days = append(days, day) months = append(months, MonthDay{ Month: month, Days: days, }) month = m day = d days = nil } else if d != day { days = append(days, day) day = d } } } days = append(days, day) months = append(months, MonthDay{ Month: month, Days: days, }) years = append(years, YearMonthDay{ Year: year, Months: months, }) return } func IndexYms(yms []int) (years []YearMonth) { if len(yms) == 0 { return } sort.Ints(yms) var ( months []int year, month int ) for _, ym := range yms { y := ym / 100 m := ym % 100 if year == 0 { // инициализация year = y month = m } else { if y != year { months = append(months, month) years = append(years, YearMonth{ Year: year, Months: months, }) year = y month = m months = nil } else if m != month { months = append(months, month) month = m } } } months = append(months, month) years = append(years, YearMonth{ Year: year, Months: months, }) return } //SELECT DATE_FORMAT(FROM_UNIXTIME(tm), '%Y%m%d') as p FROM f64 WHERE metricID IN (50) AND tm >= 1700863200 AND tm <= 1700949599 GROUP BY p;