sql:扫描具有未知列数的行(从…中选择*)

huangapple go评论84阅读模式
英文:

sql: scan row(s) with unknown number of columns (select * from ...)

问题

我有一个包含许多列的表t,我的SQL语句是这样的:select * from t。现在我只想从返回的行集中扫描一个或两个列。然而,sql.Scan接受dest ...interface{}作为参数。这是否意味着我必须扫描所有的列,然后只使用我需要的列?

我知道我可以将SQL语句从select *改为select my_favorite_rows,但在这种情况下,我无法更改SQL语句。

英文:

I have a table t containing a lot of columns, and my sql is like this: select * from t. Now I only want to scan one column or two from the wide returned row set. However, the sql.Scan accepts dest ...interface{} as arguments. Does it mean I have to scan everything and use only the column I needed?

I know I could change the sql from select * to select my_favorite_rows, however, in this case, I have no way to change the sql.

答案1

得分: 35

你可以使用Rows.Columns来获取列名,例如:

package main

import (
	"database/sql"
	"fmt"

	"github.com/lib/pq"
)

type Vehicle struct {
	Id     int
	Name   string
	Wheels int
}

// VehicleCol返回Vehicle的列的引用
func VehicleCol(colname string, vh *Vehicle) interface{} {
	switch colname {
	case "id":
		return &vh.Id
	case "name":
		return &vh.Name
	case "wheels":
		return &vh.Wheels
	default:
		panic("unknown column " + colname)
	}
}

func panicOnErr(err error) {
	if err != nil {
		panic(err.Error())
	}
}

func main() {
	conn, err := pq.ParseURL("postgres://docker:docker@172.17.0.2:5432/pgsqltest?schema=public")
	panicOnErr(err)

	var db *sql.DB
	db, err = sql.Open("postgres", conn)
	panicOnErr(err)

	var rows *sql.Rows
	rows, err = db.Query("select * from vehicle")
	panicOnErr(err)

	// 从查询中获取列名
	var columns []string
	columns, err = rows.Columns()
	panicOnErr(err)

	colNum := len(columns)

	all := []Vehicle{}

	for rows.Next() {
		vh := Vehicle{}

		// 利用VehicleCol创建列的引用
		cols := make([]interface{}, colNum)
		for i := 0; i < colNum; i++ {
			cols[i] = VehicleCol(columns[i], &vh)
		}

		err = rows.Scan(cols...)
		panicOnErr(err)

		all = append(all, vh)
	}

	fmt.Printf("%#v\n", all)
}

这是一个使用Go语言编写的示例代码,用于从数据库中查询车辆信息并打印出来。

英文:

You can make use of Rows.Columns, e.g.

package main
import (
&quot;database/sql&quot;
&quot;fmt&quot;
&quot;github.com/lib/pq&quot;
)
type Vehicle struct {
Id     int
Name   string
Wheels int
}
// VehicleCol returns a reference for a column of a Vehicle
func VehicleCol(colname string, vh *Vehicle) interface{} {
switch colname {
case &quot;id&quot;:
return &amp;vh.Id
case &quot;name&quot;:
return &amp;vh.Name
case &quot;wheels&quot;:
return &amp;vh.Wheels
default:
panic(&quot;unknown column &quot; + colname)
}
}
func panicOnErr(err error) {
if err != nil {
panic(err.Error())
}
}
func main() {
conn, err := pq.ParseURL(`postgres://docker:docker@172.17.0.2:5432/pgsqltest?schema=public`)
panicOnErr(err)
var db *sql.DB
db, err = sql.Open(&quot;postgres&quot;, conn)
panicOnErr(err)
var rows *sql.Rows
rows, err = db.Query(&quot;select * from vehicle&quot;)
panicOnErr(err)
// get the column names from the query
var columns []string
columns, err = rows.Columns()
panicOnErr(err)
colNum := len(columns)
all := []Vehicle{}
for rows.Next() {
vh := Vehicle{}
// make references for the cols with the aid of VehicleCol
cols := make([]interface{}, colNum)
for i := 0; i &lt; colNum; i++ {
cols[i] = VehicleCol(columns[i], &amp;vh)
}
err = rows.Scan(cols...)
panicOnErr(err)
all = append(all, vh)
}
fmt.Printf(&quot;%#v\n&quot;, all)
}

答案2

得分: 3

对于未知列长度,但如果您对它们的类型确定,可以使用以下代码:

    cols, err := rows.Columns()
    if err != nil {
        log.Fatal(err.Error())
    }

    colLen := len(cols)
    vals := make([]interface{}, colLen)
    for rows.Next() {
        for i := 0; i < len(colLen); i++ {
            vals[i] = new(string)
        }
        err := rows.Scan(vals...)
        if err != nil {
            log.Fatal(err.Error()) // 如果类型错误
        }

        fmt.Printf("第一列: %s\n", *(vals[0].(*string))) // 如果类型错误,将会引发 panic
    }

注意:不建议在生产环境中使用此方法。

英文:

For unknown length of columns but if you're sure about their type,

    cols, err := rows.Columns()
    if err != nil {
        log.Fatal(err.Error())
    }

    colLen := len(cols)
    vals := make([]interface{}, colLen)
    for rows.Next() {
        for i := 0; i &lt; len(colLen); i++ {
            vals[i] = new(string)
        }
        err := rows.Scan(vals...)
        if err != nil {
            log.Fatal(err.Error()) // if wrong type
        }

        fmt.Printf(&quot;Column 1: %s\n&quot;, *(vals[0].(*string))) // will panic if wrong type
    }

PS: Not recommended for prod

huangapple
  • 本文由 发表于 2014年2月17日 13:39:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/21821550.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定