Golang中SQL数值格式化JSON的方法
Golang中SQL数值格式化JSON的方法 我在使用sqlx时遇到了格式化问题
rows, err = db.Queryx(query)
for rows.Next() {
results := make(map[string]interface{})
err = rows.MapScan(results)
fmt.Fprintf(w,"%#v \n", results)
}
使用 %#v 时的输出
fmt.Fprintf(w,"%#v \n", results)
map[string]interface {}{“USER_ID”:“JD”, “USER_NAME”:“John Doe”}
map[string]interface {}{“USER_ID”:“JAD”, “USER_NAME”:“Jane Doe”}
map[string]interface {}{“USER_ID”:“DD”, “USER_NAME”:“Donald Duck”}
仅使用 %v
fmt.Fprintf(w,"%v \n", results)
map[USER_ID:JD USER_NAME:John Doe]
map[USER_ID:JAD USER_NAME:Jane Doe]
map[USER_ID:DD USER_NAME:Donald Duck]
期望的输出是去掉 map[string]interface {}
{“USER_ID”:“JD”, “USER_NAME”:“John Doe”}
{“USER_ID”:“JAD”, “USER_NAME”:“Jane Doe”}
{“USER_ID”:“DD”, “USER_NAME”:“Donald Duck”}
使用sqlx能否实现这个效果?
更多关于Golang中SQL数值格式化JSON的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你在说什么?我给了你两个例子,rows.Scan 接受的是指针数组,而不是值数组
更多关于Golang中SQL数值格式化JSON的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我被警告过不要这样做。但是手动输入成千上万个结构体可能会引发更大的恐慌 😊
vitr:
les, rows.Scan 接受一个指针数组,而不是值
是的,谢谢。但我还没弄清楚使用它们的上下文。
我一定做错了什么,得到了重复的值:
[“1”:“1”,“John Doe”:“John Doe”,“6.00”:“6.00”]
感谢提供的链接,可能非常有用。
“我宁愿使用严格的类型定义…”。对于未知表格,我该如何实现这一点?
“…或者使用第三方库进行类型转换…” - 有什么建议吗?
当你确切知道要查找什么时,查阅手册非常有价值。由于Go Playground中没有可运行的SQL示例(据我所发现的),因此很难通过实践来测试和学习。这有点像第22条军规的情况。
只是一个建议。如果没有特别充分的理由将结果放入映射中,请尽量避免这样做。映射是动态结构,必须使用互斥锁进行保护,否则在并发环境中会出现恐慌。就SQL查询而言,这会不必要地暂时减慢操作速度。建议改用扫描和结构体。
rows.Columns() 返回一个字符串切片 []string,你应该直接使用 column,而不是 column.Name()
// 示例代码
func example() {
columns, _ := rows.Columns()
for _, column := range columns {
fmt.Println(column)
}
}
请学习如何正确使用 rows.Scan 方法:https://golang.org/pkg/database/sql/#Rows,以下是我的示例:
cols := make([]interface{}, len(colNames))
colPtrs := make([]interface{}, len(colNames))
for i := 0; i < len(colNames); i++ {
colPtrs[i] = &cols[i]
}
err = rows.Scan(colPtrs...)
如果您知道表名(构建查询时必须知道),可以使用信息模式(infoschema)来获取表列信息 https://www.postgresql.org/docs/current/static/infoschema-columns.html。在那里您可以找到有关列类型的有用信息,这使您有机会将二进制数据转换为正确的类型。
这是一项繁琐的工作,我宁愿使用严格的类型定义或第三方库进行类型转换。
这很好地回答了我的问题。
但是,问题比我的原始问题更复杂。当使用 make(map[string]interface{}) 从 PostgreSQL 获取数据时,数值列被当作 Base64 处理,变得难以阅读。
这似乎是因为 Golang 的 database/sql 包或 Golang PostgreSQL 驱动程序将数值类型(现在是 []uint8)呈现给 JSON 的方式造成的。
目前我正在关注并研究这个讨论
只有在首次获取时才会不知道表结构)) 有人在数据库中创建了表,你必须将这些定义复制到代码中,开玩笑的)) Sqlboiler可以为你生成所有内容 https://github.com/volatiletech/sqlboiler 也许这些代码库也能提供帮助 https://github.com/mailru/dbr https://github.com/jmoiron/modl 一些类似的Stack Overflow回答 https://stackoverflow.com/questions/17845619/how-to-call-the-scan-variadic-function-in-golang-using-reflection/17885636#17885636 https://stackoverflow.com/questions/42774467/how-to-convert-sql-rows-to-typed-json-in-golang
将列名循环移到行循环外部解决了问题。谢谢!
var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colnames, _ := rows.Columns()
vals := make([]interface{}, len(cols))
for i, _ := range cols {
vals[i] = &cols[i]
}
mymap := make(map[string]interface{})
for i, val := range vals {
mymap[colnames[i]] = val
}
for rows.Next() {
err = rows.Scan(vals...)
json, _ := json.Marshal(mymap)
fmt.Fprintf(w,"%s\n",json)
}
这(理论上)应该能正常工作,将整数和数值转换为文本。但显然它没有正常工作,所以我想知道有没有人看出我哪里做错了?
var rows *sql.Rows
rows, err = db.Query(query)
object := map[string]interface{}{}
columns, err := rows.Columns()
values := make([]interface{}, len(columns))
for rows.Next() {
err = rows.Scan(values...)
for i, column := range columns {
object[column.Name()] = new(*string)
values[i] = object[column.Name()]
}
data, _ := json.Marshal(object)
fmt.Fprintf(w,"%s\n", data)
}
出现这个错误:
column.Name undefined (type string has no field or method Name)
我到底哪里做错了?
在转换为JSON之前需要一个映射
var rows *sql.Rows
rows, err = db.Query(query)
cols, _ := rows.Columns()
colNames, _ := rows.Columns()
vals := make([]interface{}, len(cols))
for i, _ := range cols {
vals[i] = &cols[i]
}
for rows.Next() {
var myMap = make(map[string]interface{})
err = rows.Scan(vals...)
for i, v := range vals {
myMap[colNames[i]] = v
}
json, _ := json.Marshal(myMap)
fmt.Fprintf(w,"%s\n", json)
}
添加了 colNames, _ := rows.Columns()、myMap 和一个 for 循环
是的,那个错误消失了 😊 但是没有显示任何值
var rows *sql.Rows
rows, err = db.Query(query)
object := map[string]interface{}{}
columns, _ := rows.Columns()
values := make([]interface{}, len(columns))
for rows.Next() {
err = rows.Scan(values...)
for i, column := range columns {
object[column] = new(*string)
values[i] = object[column]
}
data, _ := json.Marshal(object)
fmt.Fprintf(w,"%s\n", data)
}
localhost:8080/getuser 的结果:
{“DATE”:null,“QTY”:null,“ID”:null,“USER_NAME”:null}
{“DATE”:null,“QTY”:null,“ID”:null,“USER_NAME”:null}
现在是什么问题?
MapScan 将单行数据扫描到目标映射 map[string]interface{} 中(参考文档),这是在 Go 中打印映射的标准方式。
您可以使用 json.MarshalIndent 进行美化输出,例如:
package main
import (
"encoding/json"
"fmt"
)
func main() {
m := map[string]interface{}{"USER_ID": "JD", "USER_NAME": "John Doe"}
fmt.Println(m)
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
fmt.Println("error:", err)
}
fmt.Print(string(b))
}
最终会得到类似这样的输出:
{
"USER_ID": "JD",
"USER_NAME": "John Doe"
}
可以使用encoding/json包将map转换为JSON格式。以下是修改后的代码:
rows, err := db.Queryx(query)
for rows.Next() {
results := make(map[string]interface{})
err = rows.MapScan(results)
if err != nil {
// 处理错误
continue
}
jsonData, err := json.Marshal(results)
if err != nil {
// 处理JSON序列化错误
continue
}
fmt.Fprintf(w, "%s\n", jsonData)
}
输出结果:
{"USER_ID":"JD","USER_NAME":"John Doe"}
{"USER_ID":"JAD","USER_NAME":"Jane Doe"}
{"USER_ID":"DD","USER_NAME":"Donald Duck"}
如果需要美化输出(带缩进),可以使用json.MarshalIndent:
jsonData, err := json.MarshalIndent(results, "", " ")
if err != nil {
// 处理错误
continue
}
fmt.Fprintf(w, "%s\n", jsonData)
输出结果:
{
"USER_ID": "JD",
"USER_NAME": "John Doe"
}
{
"USER_ID": "JAD",
"USER_NAME": "Jane Doe"
}
{
"USER_ID": "DD",
"USER_NAME": "Donald Duck"
}


