首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> DB2 資料庫 >> DB2 教學

Go 語言自定型別實作 PostgreSQL Point 型別掃描與寫入

     編輯:DB2 教學

Go 語言自定型別實作 PostgreSQL Point 型別掃描與寫入

PostgreSQL 內建 point 型別(幾何點,格式 (x,y)),Go database/sql 需實作 driver.Valuer(寫入)與 sql.Scanner(掃描)介面才能直接映射結構體欄位。本文提供完整可編譯範例。

完整程式碼

package main

import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"fmt"
	"strconv"
	"strings"

	_ "github.com/lib/pq"
)

// Point 對應 PostgreSQL point 型別
type Point struct {
	X float64 `json:"lat"`
	Y float64 `json:"lng"`
}

// 實作 driver.Valuer:寫入時轉為 "(x,y)" 格式
func (p *Point) Value() (driver.Value, error) {
	buf := new(bytes.Buffer)
	fmt.Fprintf(buf, "(%f %f)", p.X, p.Y)
	return buf.Bytes(), nil
}

func (p *Point) String() string {
	return fmt.Sprintf("(%v %v)", p.X, p.Y)
}

// 實作 sql.Scanner:掃描時解析 "(x,y)" 格式
func (p *Point) Scan(val interface{}) error {
	if bb, ok := val.([]uint8); ok {
		// 移除首尾括號
		tmp := bb[1 : len(bb)-1]
		coords := strings.Split(string(tmp), ",")
		var err error
		if p.X, err = strconv.ParseFloat(coords[0], 64); err != nil {
			return err
		}
		if p.Y, err = strconv.ParseFloat(coords[1], 64); err != nil {
			return err
		}
	}
	return nil
}

type Agent struct {
	ID          int     `json:"id"`
	Name        string  `json:"name"`
	Code        string  `json:"code"`
	CSNo        string  `json:"cs_no"`
	ChannelID   int     `json:"channel_id"`
	Address     string  `json:"address"`
	Coordinate  *Point  `json:"point"`
}

func main() {
	pgURL := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=disable",
		"postgres", "123456", "localhost", "5432", "people")

	db, err := sql.Open("postgres", pgURL)
	if err != nil {
		panic(fmt.Errorf("連線失敗: %v", err))
	}
	defer db.Close()

	// 查詢掃描
	querySQL := `SELECT * FROM t_agent`
	rows, err := db.Query(querySQL)
	if err != nil {
		panic(fmt.Errorf("查詢失敗: %v", err))
	}
	defer rows.Close()

	for rows.Next() {
		ag := &Agent{Coordinate: &Point{}}
		err = rows.Scan(&ag.ID, &ag.Name, &ag.Code, &ag.CSNo, &ag.ChannelID, &ag.Address, ag.Coordinate)
		fmt.Println(ag, err)
	}

	// 插入並回傳 ID
	var id int
	err = db.QueryRow(
		`INSERT INTO t_agent (name, code, cs_no, address, coordinate) VALUES($1,$2,$3,$4,$5) RETURNING id`,
		"test1", "123457", "2", "111", "(12,43)").Scan(&id)
	fmt.Println("id:", id, "err:", err)
}

關鍵點總結

只要同時實作兩介面,*Point 即可在 rows.Scan()、QueryRow().Scan()、Exec() 參數中直接使用,型別安全且碼乾淨。

資料表結構參考

CREATE TABLE t_agent (
  id         SERIAL PRIMARY KEY,
  name       VARCHAR(100),
  code       VARCHAR(50),
  cs_no      VARCHAR(20),
  channel_id INT,
  address    VARCHAR(200),
  coordinate POINT
);
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
介面用途方法簽名
driver.ValuerGo → DB 寫入Value() (driver.Value, error)
sql.ScannerDB → Go 掃描Scan(src interface{}) error