【问题标题】:Postgresql Golang Martini Inserting keyPostgresql Golang Martini 插入密钥
【发布时间】:2015-10-23 10:11:14
【问题描述】:

我正在构建一个社交网络类型的服务器作为练习,使用 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 中的相应条目的任何建议将不胜感激......我意识到这些可能是非常愚蠢的问题,但请原谅我的天真。

【问题讨论】:

  • 感谢 AlexAtNet,我能够解决最初的问题... 有没有人对合并报表有任何建议?还是去掉多余的代码?

标签: postgresql go parameters martini


【解决方案1】:

我通过从第一个查询返回插入的用户 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。

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

【讨论】:

  • 非常感谢!我现在正在摆弄它...我仍然对如何使其工作感到有些困惑... id, err := db.Query("INSERT INTO users (first, last, email, password, karma, value) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id", 触发 sql: 转换 Exec 参数 #0 的类型: 不支持的类型 sql.Rows, 一个结构体
  • 重申一下,我正在努力解决如何访问返回的 id...'RETURNING id' 的值放在哪里?
  • 我通过将顶部查询切换到查询行并在末尾添加 .Scan(&id) 来使其工作。我很想看到一个涉及查询而不是查询行的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
  • 2011-12-17
相关资源
最近更新 更多