根据文档,在Go中从数据库中获取数据的唯一方法似乎是使用Rows.Scan(),这意味着您必须在编译时知道所有列的数量和类型。
我想念什么吗?您应该如何支持即席查询?甚至将所有列从将来可能更改的表中拉出来?
该sql.Rows类型具有Columns可以为您提供结果列名称列表的方法。可以用来确定未知查询的列数。
sql.Rows
Columns
在该Scan方法的文档中,它说:
Scan
如果参数的类型为 [] byte,则Scan会将相应数据的副本保存在该参数中。该副本归调用方所有,可以无限期修改和保存。可以通过使用 RawBytes类型的参数来避免复制。有关其使用限制,请参见RawBytes文档。 如果参数的类型为* interface {},则Scan会复制基础驱动程序提供的值,而无需进行转换。如果该值的类型为[] byte,则进行复制,并且调用方拥有结果。
如果参数的类型为 [] byte,则Scan会将相应数据的副本保存在该参数中。该副本归调用方所有,可以无限期修改和保存。可以通过使用 RawBytes类型的参数来避免复制。有关其使用限制,请参见RawBytes文档。
如果参数的类型为* interface {},则Scan会复制基础驱动程序提供的值,而无需进行转换。如果该值的类型为[] byte,则进行复制,并且调用方拥有结果。
因此,当我们不知道列值的类型时(原始格式或Go类型),我们也支持扫描列值。
将这两者放在一起,您可以使用...语法调用可变参数函数来执行以下操作:
...
columnNames, err := rows.Columns() if err != nil { log.Fatalln(err) // or whatever error handling is appropriate } columns := make([]interface{}, len(columnNames)) columnPointers := make([]interface{}, len(columnNames)) for i := 0; i < len(columnNames); i++ { columnPointers[i] = &columns[i] } if err := rows.Scan(columnPointers...); err != nil { log.Fatalln(err) }
现在,columns切片应包含当前结果行的所有列值的解码版本。
columns
如果您对表格有额外的了解(例如,预期的类型,或者提前知道列数),则可以稍微简化一下逻辑。