説明なし
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

query_csv.go 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package functions
  2. import (
  3. "database/sql"
  4. "encoding/csv"
  5. "fmt"
  6. "strings"
  7. "git.x2erp.com/qdy/go-base/ctx"
  8. "github.com/jmoiron/sqlx"
  9. )
  10. // QueryToCSV 无参数查询并返回 CSV 字节数据
  11. func QueryToCSV(db *sqlx.DB, sql string, writerHeader bool, reqCtx *ctx.RequestContext) ([]byte, error) {
  12. if sql == "" {
  13. return nil, fmt.Errorf("SQL query cannot be empty")
  14. }
  15. rows, err := db.Query(sql)
  16. if err != nil {
  17. return nil, fmt.Errorf("query execution failed: %v", err)
  18. }
  19. return rowsToCSV(rows, writerHeader)
  20. }
  21. // QueryParamsToCSV 位置参数查询并返回 CSV 字节数据
  22. func QueryPositionalToCSV(db *sqlx.DB, sql string, writerHeader bool, params []interface{}, reqCtx *ctx.RequestContext) ([]byte, error) {
  23. if sql == "" {
  24. return nil, fmt.Errorf("SQL query cannot be empty")
  25. }
  26. rows, err := db.Query(sql, params...)
  27. if err != nil {
  28. return nil, fmt.Errorf("query execution failed: %v", err)
  29. }
  30. return rowsToCSV(rows, writerHeader)
  31. }
  32. // QueryParamsNameToCSV 命名参数查询并返回 CSV 字节数据
  33. // params 可以是 map[string]interface{} 或结构体
  34. func QueryParamsNameToCSV(db *sqlx.DB, sql string, writerHeader bool, params map[string]interface{}, reqCtx *ctx.RequestContext) ([]byte, error) {
  35. if sql == "" {
  36. return nil, fmt.Errorf("SQL query cannot be empty")
  37. }
  38. query, args, err := sqlx.Named(sql, params)
  39. if err != nil {
  40. return nil, fmt.Errorf("failed to bind named parameters: %v", err)
  41. }
  42. query = db.Rebind(query)
  43. rows, err := db.Query(query, args...)
  44. if err != nil {
  45. return nil, fmt.Errorf("query execution failed: %v", err)
  46. }
  47. return rowsToCSV(rows, writerHeader)
  48. }
  49. // rowsToCSV 公共方法:将查询结果转换为 CSV 字节数据
  50. func rowsToCSV(rows *sql.Rows, writerHeader bool) ([]byte, error) {
  51. defer rows.Close()
  52. columns, err := rows.Columns()
  53. if err != nil {
  54. return nil, fmt.Errorf("failed to get columns: %v", err)
  55. }
  56. var builder strings.Builder
  57. writer := csv.NewWriter(&builder)
  58. // 根据参数决定是否写入表头
  59. if writerHeader {
  60. if err := writer.Write(columns); err != nil {
  61. return nil, fmt.Errorf("failed to write CSV header: %v", err)
  62. }
  63. }
  64. for rows.Next() {
  65. values := make([]interface{}, len(columns))
  66. valuePtrs := make([]any, len(columns))
  67. for i := range columns {
  68. valuePtrs[i] = &values[i]
  69. }
  70. if err := rows.Scan(valuePtrs...); err != nil {
  71. return nil, fmt.Errorf("failed to scan row: %v", err)
  72. }
  73. // 所有值转为字符串
  74. row := make([]string, len(columns))
  75. for i, val := range values {
  76. if val == nil {
  77. row[i] = ""
  78. } else {
  79. row[i] = fmt.Sprintf("%v", val)
  80. }
  81. }
  82. if err := writer.Write(row); err != nil {
  83. return nil, fmt.Errorf("failed to write CSV row: %v", err)
  84. }
  85. }
  86. writer.Flush()
  87. if err := writer.Error(); err != nil {
  88. return nil, fmt.Errorf("failed to flush CSV: %v", err)
  89. }
  90. if err := rows.Err(); err != nil {
  91. return nil, fmt.Errorf("row iteration error: %v", err)
  92. }
  93. return []byte(builder.String()), nil
  94. }