当前位置: 首页 > 面试题库 >

去SQL查询不一致

陶健
2023-03-14
问题内容

我在执行查询时遇到了一些非常奇怪的不一致,并且想知道是否有人知道为什么。

想象一下,我有一个结构定义如下:

type Result struct {
    Afield string      `db:"A"`
    Bfield interface{} `db:"B"`
    Cfield string      `db:"C"`
    Dfield string      `db:"D"`
}

以及具有以下列的MySQL表:

A : VARCHAR(50)
B : INT
C : VARCHAR(50)
D : VARCHAR(50)

我想执行的查询:

从表WHERE A =“ a”中选择A,B,C,D

可以执行的第一种方式:

db.Get(&result, `SELECT A, B, C, D FROM table WHERE A="a"`)

第二种可以执行的方式:

db.Get(&result, `SELECT A, B, C, D FROM table WHERE A=?`, "a")

我遇到的不一致情况如下:以第一种方式执行查询时,Bfield的类型为int。但是,第二次执行查询时为[]uint8

例如,当B为1时,就会出现这种结果。

为什么Bfield的类型根据查询的执行方式而不同?

连接声明:

// Connection is an interface for making queries.
type Connection interface {
    Exec(query string, args ...interface{}) (sql.Result, error)
    Get(dest interface{}, query string, args ...interface{}) error
    Select(dest interface{}, query string, args ...interface{}) error
}

编辑

使用Go数据库/ sql软件包+驱动程序也会发生这种情况。以下查询分别分配Bfield[]uint8int64

db的类型为* sql.DB

查询1:

db.QueryRow(SELECT A, B, C, D FROM table WHERE A="a").Scan(&result.Afield, &result.Bfield, &result.Cfield, &result.Dfield)

- >类型的BfieldIS[]uint8

查询2:

db.QueryRow(SELECT A, B, C, D FROM table WHERE A=?, "a").Scan(&result.Afield, &result.Bfield, &result.Cfield, &result.Dfield)

- >类型的BfieldISint64

编辑

其他注意事项,当链接多个WHERE子句时,只要使用填充 至少
1个?,查询将返回int。否则,如果它们都填充在字符串中,它将返回[]uint8


问题答案:

简短的答案:因为MySQL驱动程序对带有参数和不带有参数的查询使用不同的协议。使用准备好的语句以获得一致的结果。

以下说明引用了标准MySQL驱动程序github.com/go-sql-driver/mysql 1.4版

在第一种情况下,驱动程序将查询直接发送到MySQL,并将结果解释为*textRows结构。这个结构(几乎)总是将结果解码为字节片,并将转换结果转换为更好的类型给Go
sql包。这工作正常,如果目标是intstringsql.Scanner等,但不适合interface{}

在第二种情况下,驱动程序检测到有参数并返回driver.ErrSkip。这将导致Go
SQL包使用PreparedStatement。在这种情况下,MySQL驱动程序使用*binaryRows结构来解释结果。此结构使用声明的列类型(INT在这种情况下)解码值,在这种情况下将值解码为int64

有趣的事实:如果将interpolateParams=true参数提供给数据库DSN(例如"root:testing@/mysql?interpolateParams=true"),则MySQL驱动程序将在客户端准备查询,而不使用PreparedStatement。此时,两种查询的行为都相同。

一个小的概念证明:

package main

import (
    "database/sql"
    "log"

    _ "github.com/go-sql-driver/mysql"
)

type Result struct {
    Afield string
    Bfield interface{}
}

func main() {
    db, err := sql.Open("mysql", "root:testing@/mysql")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    if _, err = db.Exec(`CREATE TABLE IF NOT EXISTS mytable(A VARCHAR(50), B INT);`); err != nil {
        log.Fatal(err)
    }
    if _, err = db.Exec(`DELETE FROM mytable`); err != nil {
        log.Fatal(err)
    }
    if _, err = db.Exec(`INSERT INTO mytable(A, B) VALUES ('a', 3)`); err != nil {
        log.Fatal(err)
    }

    var (
        usingLiteral         Result
        usingParam           Result
        usingLiteralPrepared Result
    )
    row := db.QueryRow(`SELECT B FROM mytable WHERE A='a'`)
    if err := row.Scan(&usingLiteral.Bfield); err != nil {
        log.Fatal(err)
    }
    row = db.QueryRow(`SELECT B FROM mytable WHERE A=?`, "a")
    if err := row.Scan(&usingParam.Bfield); err != nil {
        log.Fatal(err)
    }
    stmt, err := db.Prepare(`SELECT B FROM mytable WHERE A='a'`)
    if err != nil {
        log.Fatal(err)
    }
    defer stmt.Close()
    row = stmt.QueryRow()
    if err := row.Scan(&usingLiteralPrepared.Bfield); err != nil {
        log.Fatal(err)
    }

    log.Printf("Type when using literal:  %T", usingLiteral.Bfield)         // []uint8
    log.Printf("Type when using param:    %T", usingParam.Bfield)           // int64
    log.Printf("Type when using prepared: %T", usingLiteralPrepared.Bfield) // int64
}


 类似资料:
  • 我对SQL还很陌生,我想看看是否可以得到一些关于减法的帮助。我想减去studentstaken-studentsnotreviewed,然后将别名total分配给操作。我在想一些关于 但有些语法问题我不太确定。 “样本数据” [所需结果]

  • 问题内容: 我只想知道如何从$ row [posts_remaining]中出现的数字中减去1 换一种说法… 这将给我我的结果,其中row posts_remaining = {THE NUMBER} 但是我想通过从中减去一个数字,然后在旧数字所在的位置设置新数字来更新返回的数字。 我希望我不要让这个令人困惑。很难解释。 另外…为了进行此操作,我是否应该将行“ posts_remaining”设置

  • 我需要以下场景的SQL查询。 @ManyToOne@JoinColumn(name=“PRODUCT_ID”)私有产品产品; 但我没有在产品中指定一个。

  • 我有两张有相同字段桌子。(请不要责怪设计)。 以下仅针对示例架构 表A ID 姓名 电话 键 所以,我想在一次查询中从满足条件“keys”的表A或表B中查询id、name,返回字段只有“id”和“name”,不管它是从表A或表B 中查询 从TABELA中选择a.id、a.name、b.id、b.name作为a,TABLEB作为b,其中a.keys=“1”或b.keys=“1” 它将重复的id、na

  • 诸葛io能够帮助企业采集和分析海量的用户行为数据,我们提供了非常灵活的可视化分析功能,能够很好的满足产品团队、市场团队、运营团队和管理决策层的日常分析需求。 但是,很多企业中会有专门的数据分析师协助业务和管理团队进行数据分析工作。针对不同的业务需求,数据分析师经常需要对用户行为数据展开更为复杂的、更为深入的查询、分析和洞察,这时,诸葛io的可视化分析功能对他们来说是不够灵活和强大的。 为此,我们提

  • 但是生成的SQL查询是 正如您所看到的,括号改变了,我相信两个查询中的条件并不相同。是虫子吗?使用hibernate和spring以及postgresql数据库。