如何从数组动态生成SQL查询列名和值?

时间:2017-11-04 17:54:44

标签: sql go

我在一行中有大约20列,并且在创建行时也不需要填写所有列我也不想在SQL查询中的每个列的cardcode名称和前端的http.post请求上。所有值均来自表单。我的代码:

var colNames, values []string

for k, v := range formData {
    colNames = append(colNames, k)
    values = append(values, v)
}

现在我有2个数组:一个有列名,第二个有要插入的值。我想做这样的事情:

db.Query("insert into views (?,?,?,?,?,?) values (?,?,?,?,?,?)", colNames..., values...)

或者像这样:

db.Query("insert into views " + colNames + " values" + values)

有什么建议吗? 谢谢!

1 个答案:

答案 0 :(得分:1)

我认为你的代码示例只是伪代码,但我会在明显的情况下陈述这些代码。

db.Query("insert into views (?,?,?,?,?,?) values (?,?,?,?,?,?)", colNames..., values...)

这是无效的Go因为你只能"解包"函数的最后一个参数,也是无效的MySQL,因为你不能使用占位符(?)作为列名。

db.Query("insert into views " + colNames + " values" + values)

这也是无效的Go因为你不能用切片连接字符串。

您可以将切片格式化为如下所示的字符串:

colNamesString := "(col1, col2, col3)"
valuesString   := "(val1, val2, val3)"

现在您的第二个代码示例变为有效Go并将编译但不执行此操作。如果您这样做,您的应用程序将容易受到SQL注入攻击,这就是您的意思绝对不想要。

而是做这样的事情:

// this can be a package level global and you'll need
// one for each table. Keep in mind that Go maps that
// are only read from are safe for concurrent use.
var validColNames = map[string]bool{
     "col1": true,
     "col2": true,
     "col3": true,
     // ...
}

// ...

var colNames, values []string
var phs string // placeholders for values

for k, v := range formData {
    // check that column is valid
    if !validColNames[k] {
        return ErrBadColName
    }
    colNames = append(colNames, k)
    values = append(values, v)
    phs += "?,"
}

if len(phs) > 0 {
    phs = phs[:len(phs)-1] // drop the last comma
}
phs = "(" + phs + ")"

colNamesString := "(" + strings.Join(colNames, ",") + ")"
query := "insert into views " + colNamesString + phs
db.Query(query, values...)