卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章35620本站已运行398

从 MySQL/Go 表获取行数据

从 mysql/go 表获取行数据

php小编小新在这篇文章中将向大家介绍如何从MySQL/Go表获取行数据。MySQL是一种流行的关系型数据库管理系统,而Go是一种强大的开发语言。在开发过程中,我们经常需要从数据库中获取数据并进行处理。本文将详细介绍如何使用Go语言连接MySQL数据库,并通过查询语句从表中获取行数据。无论您是初学者还是有经验的开发者,本文都将为您提供有用的指导和示例代码。让我们开始吧!

问题内容

首先它读取代码,以便您了解它的逻辑,当运行我捕获它的存储过程时,它会为我带来一个包含我必须返回的数据的表,列的名称确实会带来它对我来说,但列的数据没有给我带来任何东西,我无法创建模型,并且存储过程的响应有 n 个列,有 n 个不同的名称,但列的不同之处在于具有 int 数据和字符串数据,我需要您从列中捕获正确的数据,因为一切正常,但列中的数据却不起作用:

package controllers

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

type RequestData struct {
    FromData map[string]interface{} `json:"fromData"`
    Call     string                 `json:"Call"`
}

func HandleDatos(c *gin.Context) {
    var requestData RequestData

    if err := c.ShouldBindJSON(&requestData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    fmt.Printf("Ejecutando procedimiento almacenado: CALL %sn", requestData.Call)
    fmt.Printf("Parámetros: %vn", requestData.FromData)

    var rows *sql.Rows
    var err error

    // Verifica si FromData contiene valores
    if len(requestData.FromData) > 0 {
        // Si hay valores en FromData, crea una consulta con parámetros
        query := "CALL " + requestData.Call + "("
        params := []interface{}{}
        for _, value := range requestData.FromData {
            query += "?, "
            params = append(params, value)
        }
        query = query[:len(query)-2] + ")"

        rows, err = db.Raw(query, params...).Rows()
    } else {
        // Si no hay valores en FromData, ejecuta el procedimiento almacenado sin parámetros
        rows, err = db.Raw("CALL " + requestData.Call).Rows()
    }

    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    defer rows.Close()

    // Convierte los resultados en un mapa
    result := make(map[string]interface{})
    columns, err := rows.Columns()
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    fmt.Printf("Columnas: %vn", columns) // Punto de impresión

    data := [][]interface{}{} // Almacena los datos de filas
    for rows.Next() {
        values := make([]interface{}, len(columns))
        for i := range columns {
            values[i] = new(interface{})
        }

        if err := rows.Scan(values...); err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }

        fmt.Printf("Valores escaneados: %vn", values) // Punto de impresión

        row := make(map[string]interface{})
        for i, col := range columns {
            val := *(values[i].(*interface{}))
            row[col] = val
        }

        fmt.Printf("Fila escaneada: %vn", row) // Punto de impresión

        // Agrega esta fila al resultado
        data = append(data, values)
    }

    fmt.Printf("Datos finales: %vn", data) // Punto de impresión

    if len(data) > 0 {
        result["columns"] = columns
        result["data"] = data
    } else {
        // Si no hay datos, establece un mensaje personalizado
        result["message"] = "Sin datos"
    }

    // Convierte el resultado en JSON y devuelve la respuesta
    responseJSON, err := json.Marshal(result)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, string(responseJSON))
}

这就是它返回给我的内容,其中显示“columns”:[“idPunto”,“nombre”]该部分没问题,但包含数据的行不是我所期望的:

解决方法

将行扫描到接口{}中不会自动将 SQL 类型转换为 Go 类型。相反,使用 ColumnTypes 方法将获取每列的数据类型,允许您动态分配正确的 Go 类型。 (以下内容未经测试,仅供参考。)例如

for i := range columns {
    // Use the column types to determine the appropriate scan type
    switch columnTypes[i].DatabaseTypeName() {
    case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT":
        scanArgs[i] = new(int64)
    default:
        scanArgs[i] = new(string)
    }

    values[i] = scanArgs[i]
}

在您的脚本中:

package controllers

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

type RequestData struct {
    FromData map[string]interface{} `json:"fromData"`
    Call     string                 `json:"Call"`
}

func HandleDatos(c *gin.Context) {
    var requestData RequestData

    if err := c.ShouldBindJSON(&requestData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    fmt.Printf("Ejecutando procedimiento almacenado: CALL %sn", requestData.Call)
    fmt.Printf("Parámetros: %vn", requestData.FromData)

    var rows *sql.Rows
    var err error

    // Verifica si FromData contiene valores
    if len(requestData.FromData) > 0 {
        // Si hay valores en FromData, crea una consulta con parámetros
        query := "CALL " + requestData.Call + "("
        params := []interface{}{}
        for _, value := range requestData.FromData {
            query += "?, "
            params = append(params, value)
        }
        query = query[:len(query)-2] + ")"

        rows, err = db.Raw(query, params...).Rows()
    } else {
        // Si no hay valores en FromData, ejecuta el procedimiento almacenado sin parámetros
        rows, err = db.Raw("CALL " + requestData.Call).Rows()
    }

    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }
    defer rows.Close()

    // Convierte los resultados en un mapa
    result := make(map[string]interface{})
    columns, err := rows.Columns()
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    fmt.Printf("Columnas: %vn", columns) // Punto de impresión

    data := []map[string]interface{}{} // Almacena los datos de filas

    // Get the column types
    columnTypes, err := rows.ColumnTypes()
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    for rows.Next() {
        values := make([]interface{}, len(columns)
        scanArgs := make([]interface{}, len(columns))

        for i := range columns {
            // Use the column types to determine the appropriate scan type
            switch columnTypes[i].DatabaseTypeName() {
            case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT":
                scanArgs[i] = new(int64)
            default:
                scanArgs[i] = new(string)
            }

            values[i] = scanArgs[i]
        }

        if err := rows.Scan(values...); err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
            return
        }

        fmt.Printf("Valores escaneados: %vn", values) // Punto de impresión

        row := make(map[string]interface{})
        for i, col := range columns {
            // Cast the scanned values to the appropriate data types
            switch columnTypes[i].DatabaseTypeName() {
            case "INT", "TINYINT", "SMALLINT", "MEDIUMINT", "BIGINT":
                row[col] = *(scanArgs[i].(*int64))
            default:
                row[col] = *(scanArgs[i].(*string))
            }
        }

        fmt.Printf("Fila escaneada: %vn", row) // Punto de impresión

        // Agrega esta fila al resultado
        data = append(data, row)
    }

    fmt.Printf("Datos finales: %vn", data) // Punto de impresión

    if len(data) > 0 {
        result["columns"] = columns
        result["data"] = data
    } else {
        // Si no hay datos, establece un mensaje personalizado
        result["message"] = "Sin datos"
    }

    // Convierte el resultado en JSON y devuelve la respuesta
    responseJSON, err := json.Marshal(result)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    c.JSON(http.StatusOK, string(responseJSON))
}

nb:您应该能够针对可能遇到的其他数据类型扩展此逻辑。

卓越飞翔博客
上一篇: 如何在go和c#控制台应用程序之间建立长期管道连接
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏