PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Cláusula Go e IN no Postgres

Pré-construindo a consulta SQL (evitando injeção de SQL)


Se você estiver gerando uma string SQL com um placeholder param para cada um dos valores, é mais fácil gerar o SQL final imediatamente.

Observe que, como os valores são string s, há lugar para o ataque de injeção de SQL, então primeiro testamos se todas as string os valores são de fato números, e só procedemos se assim for:
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(")")

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

Usando ANY


Você também pode usar o ANY do Postgresql , cuja sintaxe é a seguinte:
expression operator ANY (array expression)

Usando isso, nossa consulta pode ficar assim:
SELECT COUNT(id) FROM tags WHERE id = ANY('{1,2,3}'::int[])

Nesse caso, você pode declarar o formato de texto do array como parâmetro:
SELECT COUNT(id) FROM tags WHERE id = ANY($1::int[])

Que pode ser simplesmente construído assim:
tags := []string{"1", "2", "3"}
param := "{" + strings.Join(tags, ",") + "}"

Observe que nenhuma verificação é necessária neste caso, pois a expressão de matriz não permitirá injeção de SQL (mas resultará em um erro de execução de consulta).

Então o 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)
}