去SQL查询不一致

时间:2019-02-22 19:21:37

标签: sql go sqlx

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

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

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)

-> Bfield的类型为[]uint8

查询2:

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

-> Bfield的类型为int64

编辑

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

2 个答案:

答案 0 :(得分:2)

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

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

在第一种情况下,驱动程序将查询直接发送到MySQL,并将结果解释为Picture.Bitmap结构。该结构(几乎)始终为decodes results into a byte slice,并将转换为更好的类型留给Go Imagem.Picture.Graphic.SaveToStream(Memoria); 包。如果目标是*textRowssqlint等,但是对于string则无效。

在第二种情况下,the driver detects that there are arguments and returns driver.ErrSkip。这将导致Go SQL程序包使用PreparedStatement。在这种情况下,MySQL驱动程序使用sql.Scanner结构来解释结果。 This struct uses the declared column type (INT in this case) to decode the value,在这种情况下,将值解码为interface{}

有趣的事实:如果您向数据库DSN提供*binaryRows参数(例如int64),则MySQL驱动程序将在客户端准备查询,而不使用PreparedStatement。此时,两种查询的行为都相同。

一个小的概念证明:

interpolateParams=true

答案 1 :(得分:0)

您的第一个SQL字符串(在MySql中是模棱两可的,并且可能具有太深的含义,如以下地址中StackOverflow所述

When to use single quotes, double quotes, and back ticks in MySQL

根据SQL-MODE,您的SQL命令可以解释为

SELECT A, B, C, D FROM table WHERE A='a'

那是我想你所期望的。

或为

SELECT A, B, C, D FROM table WHERE A=`a`

为避免这种歧义,您是否可以进行新的FIRST测试以将双引号替换为单引号?

如果仍然存在相同的行为,则我的回答不是很好的答案。

如果两个SQL选择都返回相同的值,则您的问题已解决。

使用`字符,您传递的是变量名而不是字符串值!