PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Go et clause IN dans Postgres

Pré-construire la requête SQL (empêcher l'injection SQL)

Si vous générez une chaîne SQL avec un paramètre fictif pour chacune des valeurs, il est plus simple de générer immédiatement le SQL final.

Notez que puisque les valeurs sont string s, il y a de la place pour l'attaque par injection SQL, donc nous testons d'abord si toute la string les valeurs sont en effet des nombres, et nous ne procédons que si c'est le cas :

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(")")

Exécution :

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

Utiliser ANY

Vous pouvez également utiliser le ANY de Postgresql , dont la syntaxe est la suivante :

expression operator ANY (array expression)

En utilisant cela, notre requête peut ressembler à ceci :

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

Dans ce cas, vous pouvez déclarer la forme textuelle du tableau en paramètre :

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

Qui peut simplement être construit comme ceci :

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

Notez qu'aucune vérification n'est requise dans ce cas car l'expression de tableau n'autorisera pas l'injection SQL (mais entraînera plutôt une erreur d'exécution de la requête).

Donc le code complet :

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)
}