0

我正在使用 martini、golang 和 postgresql 构建一个社交网络类型的服务器作为练习,以帮助发展我在这三个方面的技能。几个关键的事情是如何将用户表中的主键插入用户信息表的正确行(以将用户信息与特定用户连接起来)。我相信还有一种方法可以将两个查询合并到一个更简洁的 postgres 脚本中......

func CreateUser(ren render.Render, r *http.Request, db *sql.DB) {

  _, err := db.Query("INSERT INTO users (first, last, email, password, karma, value) SELECT  CAST ($3 AS VARCHAR), $1, $2, $4, $5, $6 WHERE NOT EXISTS (SELECT * FROM users WHERE email = $3)",
    r.FormValue("first"),
    r.FormValue("last"),
    r.FormValue("email"),
    r.FormValue("password"),
    0,
    0)

  PanicIf(err)

  _, err = db.Query("INSERT INTO userinfo (usr, dob, phonenum, bio, mates, bought, sold) VALUES ($1, $2, $3, $4, $5, $6, $7)",
        0,
        r.FormValue("dob"),
        r.FormValue("phonenum"),
        r.FormValue("bio"),
        0,
        0,
        0)

  PanicIf(err)

  ren.Redirect("/")
}

下面是创建用户表的脚本:

DROP TABLE IF EXISTS "public"."users";
CREATE TABLE "public"."users" (
    "id" serial NOT NULL,
    "first" varchar(40) NOT NULL COLLATE "default",
    "last" varchar(40) NOT NULL COLLATE "default",
    "email" varchar(40) NOT NULL COLLATE "default",
    "password" varchar(40) NOT NULL COLLATE "default",
    "karma" int NOT NULL,
    "value" int NOT NULL
)
WITH (OIDS=FALSE);

我意识到在生产级代码中我不想像这样存储密码。我也对如何将非全局参数拉入数据库感到困惑,因为它是由 m.get 和 m.post 命令创建的。

 m.Post("/newuser", CreateUser)
 m.Get("/user", NewUser)

任何关于将用户的密钥合并和添加到 userinfo 中的适当条目的任何建议都将不胜感激......我意识到这些可能是非常愚蠢的问题,但请原谅我的天真。

4

1 回答 1

0

我通过从第一个查询返回插入的用户 ID 并在第二个查询中使用它来做到这一点,但我没有使用 upsert。

因此,您可以尝试使用RETURNING返回新添加用户的 id 或通过电子邮件单独查询(因为在这种情况下,每个用户的电子邮件看起来都是唯一的)。

然后将其用于第二个查询:

_, err = db.Query(`INSERT INTO userinfo (usr, dob, phonenum, bio, mates, bought, sold)
                   VALUES ($1, $2, $3, $4, $5, $6, $7)`,
    id, // there
    r.FormValue("dob"),
    r.FormValue("phonenum"),
    ...

我想那usr是用户ID(外键users.id

示例源代码:

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/lib/pq"
    "log"
)

func main() {
    db, err := sql.Open("postgres", "user=alex dbname=tmp sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }

    rows, err := db.Query(`
        INSERT INTO users (first, last, email, password, karma, value)
        SELECT  CAST ($3 AS VARCHAR), $1, $2, $4, $5, $6
        WHERE NOT EXISTS (SELECT * FROM users WHERE email = $3)
        RETURNING id`,
        "first", "last", "email", "password", 0, 0)
    defer rows.Close()
    if err != nil {
        log.Fatal(err)
    }

    if rows.Next() {
        id := 0
        rows.Scan(&id)
        _, err = db.Exec(`INSERT INTO userinfo (user_id, info) VALUES ($1, $2)`, id, "info")
        if err != nil {
            log.Fatal(err)
        }

        fmt.Println("Inserted:", id)
    }

}

我个人更喜欢 QueryRow 而不是 query,因为返回一行更明显,但它也适用于 Query。

我还建议对电子邮件使用唯一索引,而不是子查询。

于 2015-07-31T17:22:10.530 回答