Golang如何从数据库中获取可用表
Golang如何从数据库中获取可用表 我正在尝试编写一个ODBC适配器,它将接收驱动程序类型和数据源,并建立与数据库的连接。传递数据源让我感到困惑。 有人能帮我理解如何实现这个目标吗?
package odbcstream
import (
"database/sql"
"fmt"
_"github.com/alexbrainman/odbc"
)
// 指向数据库实例的指针
var DBClient *sql.DB
// 初始化数据源凭证的变量
var server, user, password, database string
type Table struct {
name string
}
// 初始化与所选数据库的连接
func InitialiseDBConnection(driverType, dataSourceName string) error{
dataSourceName = fmt.Sprintf("server=%s;user id=%s;password=%s;database=%s;",
server, user, password, database)
db, err := sql.Open(driverType, dataSourceName)
if err != nil {
panic(err.Error())
}
// 检查数据库是否已连接
err = db.Ping()
if err != nil {
panic(err.Error())
}
DBClient = db
return db.Close()
}
// 获取数据库中的表列表
func List(t *Table) {
var tables []Table
ta, err := DBClient.Query("SELECT * FROM sys.Table")
if err != nil {
panic(err.Error())
}
for ta.Next() {
var table Table
if err := ta.Scan(&table.name); err != nil {
fmt.Println("An error scanning for tables", err)
return
}
tables = append(tables, table )
}
}
package main
import (
"odbcstream/odbcstream"
// "fmt"
)
func main() {
// psql 是 "driver" 类型,"france" 是数据源
odbcstream.InitialiseDBConnection("psql", "france")
// fmt.Println("Hello Go")
}
更多关于Golang如何从数据库中获取可用表的实战教程也可以访问 https://www.itying.com/category-94-b0.html
非常感谢您分享的知识和经验。我实际上是Go语言和数据库管理系统的新手,但我非常感激您的澄清和解释。
更多关于Golang如何从数据库中获取可用表的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢您的努力。实际上,我想通过ODBC适配器接口安全地连接到任何数据库(例如:PostgreSQL、MySQL、MSSQL等),并检索在指定为数据库源的源中可用的表。
我原以为ODBC可以替代底层的驱动程序类型,无论是PostgreSQL、MSSQL等,我只需在函数参数中指定数据库使用的驱动程序类型即可。 是否有更好的方法来实现这一点? 我乐于学习,请指教。
Oyemechi:
将数据源传递到一个幻象中对我来说难以理解。
我不知道你在寻找什么,但我正在努力解决一个类似的问题。有些部分已经接近解决。 http://94.237.92.101:6060/api
Oyemechi:
我以为ODBC可以替代底层的驱动程序类型。
我个人认为,专注于一个特定的数据库系统,而非使用通用驱动程序,才能最大程度地发挥关系型数据库管理系统的优势。举个例子,PostgreSQL 中的简单 WITH 子句功能已经存在多年,而 MySQL 直到最近才支持。缺少某些功能会限制你编写高效 SQL 查询的能力。如果你使用通用驱动程序,我猜你只能使用所有数据库都支持的最基础功能,这无疑会限制查询的可能性。
同样的观点也适用于任何通用的对象关系映射工具,它们同样会限制编写复杂 SQL 查询的能力。这种“魔法”迟早会带来限制。
我使用 PostgreSQL 已近十年,它一直非常稳定可靠,并且允许你在同一个数据库中混合使用 NoSQL 和 SQL 操作。
最后,我认为还有一点很重要。当你需要社区帮助时,我注意到,对于使用任何形式的未知“中间件”所提出的问题,得到的回答往往较少,因为特定代码组合的知识是有限的。
在Golang中从数据库获取可用表的方法取决于具体的数据库类型。以下是针对不同数据库的通用实现方法:
1. 修复你的ODBC连接实现
首先,你的数据源传递方式需要调整:
func InitialiseDBConnection(driverType, dataSourceName string) error {
// 直接使用传入的dataSourceName,而不是重新构建
db, err := sql.Open(driverType, dataSourceName)
if err != nil {
return fmt.Errorf("failed to open database: %v", err)
}
// 检查数据库是否已连接
if err = db.Ping(); err != nil {
return fmt.Errorf("failed to ping database: %v", err)
}
DBClient = db
return nil // 不要在这里关闭连接!
}
2. 通用表查询方法
// 获取所有表名
func GetAllTables() ([]string, error) {
var tables []string
// 通用SQL查询(需要根据数据库类型调整)
query := `
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
`
rows, err := DBClient.Query(query)
if err != nil {
// 如果通用查询失败,尝试特定数据库的查询
return getTablesByDriver()
}
defer rows.Close()
for rows.Next() {
var tableName string
if err := rows.Scan(&tableName); err != nil {
return nil, fmt.Errorf("scan error: %v", err)
}
tables = append(tables, tableName)
}
return tables, nil
}
3. 根据数据库类型获取表
func getTablesByDriver() ([]string, error) {
var tables []string
var query string
// 根据驱动类型使用不同的系统表查询
switch driverType {
case "postgres", "pgx":
query = "SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname != 'pg_catalog' AND schemaname != 'information_schema'"
case "mysql":
query = "SHOW TABLES"
case "sqlserver", "mssql":
query = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'"
case "sqlite3":
query = "SELECT name FROM sqlite_master WHERE type='table'"
case "odbc":
// ODBC通用查询
query = "SELECT table_name FROM information_schema.tables"
default:
return nil, fmt.Errorf("unsupported driver type: %s", driverType)
}
rows, err := DBClient.Query(query)
if err != nil {
return nil, fmt.Errorf("query error: %v", err)
}
defer rows.Close()
for rows.Next() {
var tableName string
if err := rows.Scan(&tableName); err != nil {
return nil, fmt.Errorf("scan error: %v", err)
}
tables = append(tables, tableName)
}
return tables, nil
}
4. 改进的Table结构和方法
type TableInfo struct {
TableName string
TableSchema string
TableType string
CreateTime sql.NullTime
}
// 获取详细的表信息
func GetTableDetails() ([]TableInfo, error) {
var tables []TableInfo
query := `
SELECT
table_name,
table_schema,
table_type,
create_time
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema', 'pg_catalog', 'sys')
ORDER BY table_schema, table_name
`
rows, err := DBClient.Query(query)
if err != nil {
return nil, fmt.Errorf("query error: %v", err)
}
defer rows.Close()
for rows.Next() {
var table TableInfo
if err := rows.Scan(&table.TableName, &table.TableSchema,
&table.TableType, &table.CreateTime); err != nil {
return nil, fmt.Errorf("scan error: %v", err)
}
tables = append(tables, table)
}
return tables, nil
}
5. 使用示例
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/alexbrainman/odbc"
)
func main() {
// ODBC连接字符串示例
dsn := "Driver={SQL Server};Server=localhost;Database=testdb;Trusted_Connection=yes;"
// 初始化连接
db, err := sql.Open("odbc", dsn)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 获取所有表
tables, err := GetAllTables(db)
if err != nil {
log.Fatal(err)
}
fmt.Println("Available tables:")
for _, table := range tables {
fmt.Printf("- %s\n", table)
}
}
// 独立函数版本
func GetAllTables(db *sql.DB) ([]string, error) {
var tables []string
// 尝试多种查询方法
queries := []string{
"SELECT name FROM sysobjects WHERE xtype='U'", // SQL Server
"SELECT table_name FROM information_schema.tables",
"SHOW TABLES", // MySQL
}
for _, query := range queries {
rows, err := db.Query(query)
if err == nil {
defer rows.Close()
for rows.Next() {
var tableName string
if err := rows.Scan(&tableName); err == nil {
tables = append(tables, tableName)
}
}
if len(tables) > 0 {
return tables, nil
}
}
}
return tables, fmt.Errorf("unable to retrieve tables")
}
6. 处理特定数据库的系统表
// 获取SQL Server的表
func GetSQLServerTables(db *sql.DB) ([]string, error) {
var tables []string
rows, err := db.Query(`
SELECT s.name + '.' + t.name
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
ORDER BY s.name, t.name
`)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var tableName string
if err := rows.Scan(&tableName); err != nil {
return nil, err
}
tables = append(tables, tableName)
}
return tables, nil
}
关键点:
- 数据源名称应该直接传递给
sql.Open(),而不是在函数内部重新构建 - 不同数据库有不同的系统表查询方式
- 使用
information_schema.tables是跨数据库的通用方法 - 需要处理不同驱动类型的特定查询语法

