Golang中如何处理PostgreSQL的多结果集查询

Golang中如何处理PostgreSQL的多结果集查询 大家好,我在Postgres数据库中有一个函数,它返回一组refcursors(4个)。如何在不知道refcursors名称的情况下获取数据?我认为应该有一种通过编程方式获取游标名称的方法,希望这说得通。

import (
	"database/sql"
	"fmt"
	"log"
	_ "github.com/lib/pq"
)

const (
	host     = "ip address goes here"
	port     = 5432
	user     = "postgres"
	password = "*********"
	dbname   = "*********"
)

func main() {
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, port, user, password, dbname)

	db, err := sql.Open("postgres", psqlInfo)

	if err != nil {
		log.Fatal(err)
	}

	defer db.Close()
	tx, err := db.Begin()
    // 这个函数返回4个游标
	row := tx.QueryRow("SELECT public.spgetinvoicedata();")
    var CursorName string
	
    // 这里返回第一个游标的名称
	err = row.Scan(&CursorName)
	
	rows1, err := tx.Query("FETCH all from " + CursorName + ";" )
      
    // 现在rows1中有数据
    // 如何获取其他游标的名称
}

更多关于Golang中如何处理PostgreSQL的多结果集查询的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何处理PostgreSQL的多结果集查询的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在PostgreSQL中,当存储过程返回多个refcursor时,您可以使用pg_cursor系统视图来动态获取所有打开的游标名称。以下是完整的解决方案:

import (
    "database/sql"
    "fmt"
    "log"
    _ "github.com/lib/pq"
)

func main() {
    psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
        host, port, user, password, dbname)

    db, err := sql.Open("postgres", psqlInfo)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    tx, err := db.Begin()
    if err != nil {
        log.Fatal(err)
    }
    defer tx.Rollback()

    // 执行存储过程
    _, err = tx.Exec("SELECT public.spgetinvoicedata()")
    if err != nil {
        log.Fatal(err)
    }

    // 查询当前事务中打开的游标
    cursorRows, err := tx.Query(`
        SELECT name FROM pg_cursors 
        WHERE statement = 'SELECT public.spgetinvoicedata()'
    `)
    if err != nil {
        log.Fatal(err)
    }
    defer cursorRows.Close()

    var cursorNames []string
    for cursorRows.Next() {
        var cursorName string
        if err := cursorRows.Scan(&cursorName); err != nil {
            log.Fatal(err)
        }
        cursorNames = append(cursorNames, cursorName)
    }

    if err := cursorRows.Err(); err != nil {
        log.Fatal(err)
    }

    // 遍历所有游标获取数据
    for i, cursorName := range cursorNames {
        fmt.Printf("Processing cursor %d: %s\n", i+1, cursorName)
        
        rows, err := tx.Query("FETCH ALL FROM " + cursorName)
        if err != nil {
            log.Fatal(err)
        }
        defer rows.Close()

        // 获取列信息
        columns, err := rows.Columns()
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("Columns for cursor %s: %v\n", cursorName, columns)

        // 处理数据行
        for rows.Next() {
            // 根据实际表结构创建相应变量
            // 这里使用通用方式处理
            values := make([]interface{}, len(columns))
            valuePtrs := make([]interface{}, len(columns))
            
            for i := range values {
                valuePtrs[i] = &values[i]
            }
            
            if err := rows.Scan(valuePtrs...); err != nil {
                log.Fatal(err)
            }
            
            // 处理每一行数据
            fmt.Printf("Row data: %v\n", values)
        }
        
        if err := rows.Err(); err != nil {
            log.Fatal(err)
        }
    }

    if err := tx.Commit(); err != nil {
        log.Fatal(err)
    }
}

如果您需要更精确地识别特定存储过程返回的游标,可以使用这个替代方案:

// 替代方案:通过游标创建时间识别
cursorRows, err := tx.Query(`
    SELECT name FROM pg_cursors 
    WHERE substring(statement from 1 for 30) = 'SELECT public.spgetinvoicedata'
    ORDER BY creation_time
`)
if err != nil {
    log.Fatal(err)
}
defer cursorRows.Close()

如果您知道游标的数量但不知道名称,也可以使用这种方法:

// 如果知道有4个游标
cursorRows, err := tx.Query(`
    SELECT name FROM pg_cursors 
    WHERE statement LIKE 'SELECT public.spgetinvoicedata%'
    LIMIT 4
`)
if err != nil {
    log.Fatal(err)
}
defer cursorRows.Close()

这种方法通过查询PostgreSQL的系统视图pg_cursors来动态获取当前事务中所有打开的游标名称,然后逐个处理每个游标的数据。

回到顶部