sql >> Base de Datos >  >> RDS >> PostgreSQL

Cláusula Go e IN en Postgres

Preconstruir la consulta SQL (prevenir la inyección de SQL)

Si está generando una cadena SQL con un marcador de posición param para cada uno de los valores, es más fácil generar el SQL final de inmediato.

Tenga en cuenta que dado que los valores son string s, hay lugar para el ataque de inyección SQL, por lo que primero probamos si toda la string los valores son de hecho números, y solo procedemos si es así:

tags := []string{"1", "2", "3"}
buf := bytes.NewBufferString("SELECT COUNT(id) FROM tags WHERE id IN(")
for i, v := range tags {
    if i > 0 {
        buf.WriteString(",")
    }
    if _, err := strconv.Atoi(v); err != nil {
        panic("Not number!")
    }
    buf.WriteString(v)
}
buf.WriteString(")")

Ejecutarlo:

num := 0
if err := Db.QueryRow(buf.String()).Scan(&num); err != nil {
    log.Println(err)
}

Usando ANY

También puede usar ANY de Postgresql , cuya sintaxis es la siguiente:

expression operator ANY (array expression)

Usando eso, nuestra consulta puede verse así:

SELECT COUNT(id) FROM tags WHERE id = ANY('{1,2,3}'::int[])

En este caso, puede declarar la forma de texto de la matriz como un parámetro:

SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])

Que simplemente se puede construir así:

tags := []string{"1", "2", "3"}
param := "{" + strings.Join(tags, ",") + "}"

Tenga en cuenta que no se requiere verificación en este caso ya que la expresión de la matriz no permitirá la inyección de SQL (sino que dará como resultado un error de ejecución de la consulta).

Así que el código completo:

tags := []string{"1", "2", "3"}

q := "SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])"
param := "{" + strings.Join(tags, ",") + "}"

num := 0
if err := Db.QueryRow(q, param).Scan(&num); err != nil {
    log.Println(err)
}