Нельзя использовать буфер (тип bytes.Buffer) в качестве строки типа в аргументе для db.Query

Я написал SQL-запрос в buffer.WriteString(), но не смог использовать этот буфер в db.Query().

buffer.WriteString(fmt.Sprintf(`SELECT c.id, c.company_name, ss.start_date, ss.shift_length, ss.bill_rate, ss.ot_hrs, ss.dt_hrs, ts.pay_rate, ts.wc_rate, ts.paid, td.wc
        FROM company c
        JOIN users u1 ON c.id = u1.company_id
        JOIN schedule s ON u1.id = s.user_id
        JOIN schedule_shifts ss ON s.id = ss.schedule_id
        JOIN technician_shifts ts ON ss.id = ts.shift_id
        JOIN users u ON u.id = ts.technician_id
        JOIN technician_details td ON td.user_id = u.id
        JOIN master_technicians mt ON mt.id = u.master_technician_id
        WHERE mt.id = %d AND ts.confirmed = 'yes' AND ts.paid = 'yes'`, masterID))

    if e.Type == "today" {
        buffer.WriteString(fmt.Sprintf(`AND ts.paid_on = CURDATE()`))
    } else if e.Type == "weekly" {
        buffer.WriteString(fmt.Sprintf(`AND ts.paid_on > DATE_SUB(NOW(), INTERVAL 1 WEEK)`))
    } else if e.Type == "monthly" {
        buffer.WriteString(fmt.Sprintf(`AND ts.paid_on > DATE_SUB(NOW(), INTERVAL 1 MONTH)`))
    } else {
        if e.StartDate != "" && e.EndDate != "" {
            if e.StartDate == e.EndDate {
                buffer.WriteString(fmt.Sprintf(`AND ts.paid_on = %s`, e.StartDate))
            } else {
                buffer.WriteString(fmt.Sprintf(`AND ts.paid_on >= %s AND ts.paid_on <= %s`, e.StartDate, e.EndDate))
            }
        }
    }

rows, err := db.Query(buffer)
    if err != nil {
        log.Panic(err.Error())
    }

Это дает мне ошибку, что

cannot use buffer (type bytes.Buffer) as type string in argument to db.Query

Как я могу это сделать?

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
1
0
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Прямой ответ на ваш вопрос — предоставлено документами, и он заключается в простом использовании метода String():

rows, err := db.Query(buffer.String())

Сказав это, буфер, вероятно, не имеет здесь смысла. Для построения строк тип strings.Builder более эффективен.

Но в вашем конкретном случае создание SQL-запросов таким образом опасно и чревато ошибками. Несколько предложений:

  1. НИКОГДА, НИКОГДА использует конкатенацию строк или Sprintf/Fprintf для вставки значений в SQL-запросы. Вы откроете себя для атак SQL-инъекций. Вместо этого всегда используйте параметризованные запросы.
  2. Большие блоки if/else подвержены ошибкам и плохо читаются. Вместо этого используйте правильный оператор switch.
  3. Вы можете использовать построитель запросов SQL, но в вашем случае у вас есть только одна необязательная часть запроса. Просто используйте для этого стандартную конкатенацию строк.

Я переписал ваш код с учетом вышеуказанных проблем, и теперь он выглядит так:

var paidCondition string
args := []interface{}{masterID}
switch (
case e.Type == "today":
    paidCondition = `AND ts.paid_on = CURDATE()`
case e.Type == "weekly":
    paidCondition = `AND ts.paid_on > DATE_SUB(NOW(), INTERVAL 1 WEEK)`
case e.Type == "monthly":
    paidCondition = `AND ts.paid_on > DATE_SUB(NOW(), INTERVAL 1 MONTH)`
case e.StartDate != "" && e.EndDate != "" && e.StartDate == e.EndDate:
    paidCondition = `AND ts.paid_on = ?`
    args = append(args, e.StartDate)
case e.StartDate != "" && e.EndDate != "":
    paidCondition = `AND ts.paid_on >= ? AND ts.paid_on <= ?`
    args = append(args, e.StartDate, e.EndDate)
)

query := `SELECT c.id, c.company_name, ss.start_date, ss.shift_length, ss.bill_rate, ss.ot_hrs, ss.dt_hrs, ts.pay_rate, ts.wc_rate, ts.paid, td.wc
    FROM company c
    JOIN users u1 ON c.id = u1.company_id
    JOIN schedule s ON u1.id = s.user_id
    JOIN schedule_shifts ss ON s.id = ss.schedule_id
    JOIN technician_shifts ts ON ss.id = ts.shift_id
    JOIN users u ON u.id = ts.technician_id
    JOIN technician_details td ON td.user_id = u.id
    JOIN master_technicians mt ON mt.id = u.master_technician_id
    WHERE mt.id = ? AND ts.confirmed = 'yes' AND ts.paid = 'yes' ` + paidCondition

rows, err := db.Query(query, args...)
if err != nil {
    log.Panic(err.Error())
}

И, наконец, пара других улучшений, которые не имеют прямого отношения к вашему вопросу или предложенному мной коду выше:

  1. buffer.WriteString(fmt.Sprintf(...)) слишком многословен. Более короткая версия: fmt.Fprintf(buffer,...).
  2. Вы используете fmt.Sprintf() в нескольких местах, где форматирование не выполняется. Просто удалите это полностью. Например, замените fmt.Sprintf("AND ts.paid_on = CURDATE()") на просто "AND ts.paid_on = CURDATE()".

1. точнее не использовать их для проставления значения в запросах. Нет ничего плохого в том, чтобы собрать динамический запрос с помощью этих инструментов, если это все еще параметризованный/подготовленный запрос.

Adrian 29.05.2019 15:12

Другие вопросы по теме