2015-02-21 10 views
9

मैं डेटाबेस तालिका से मूल्यों को पढ़ने और तालिका में प्रिंट करने के लिए एक मूल प्रोग्राम लिख रहा हूं। तालिका एक प्राचीन कार्यक्रम द्वारा आबादी थी। पंक्ति में कुछ फ़ील्ड वैकल्पिक हैं और जब मैं उन्हें स्ट्रिंग के रूप में पढ़ने की कोशिश, मैं निम्नलिखित त्रुटि मिलती है:मैं डेटाबेस से शून्य वापसी मान कैसे संभाल सकता हूं?

panic: sql: Scan error on column index 2: unsupported driver -> Scan pair: <nil> -> *string 

बाद मैं इसी तरह के मुद्दों के लिए अन्य प्रश्न पढ़ा है, मैं निम्नलिखित कोड को संभालने के लिए के साथ आया था शून्य मूल्य विधि अभ्यास में ठीक काम करता है। मुझे शून्य मानों के बजाय सादा पाठ और खाली स्ट्रिंग में मान मिलते हैं।

  1. यह कुशल नहीं लगती है:

    हालांकि, मैं दो चिंताएं हैं। मुझे इस तरह के 25+ फ़ील्ड को संभालने की ज़रूरत है और इसका मतलब यह होगा कि मैं उनमें से प्रत्येक को बाइट्स के रूप में पढ़ता हूं और स्ट्रिंग में परिवर्तित करता हूं। बहुत अधिक फ़ंक्शन कॉल और रूपांतरण। डेटा को संभालने के लिए दो structs ...

  2. कोड बदसूरत लग रहा है। यह पहले से ही 2 फ़ील्ड के साथ घिरा हुआ दिख रहा है और मैं 25 +

पर जा रहा हूं, तो मैं इसे गलत कर रहा हूं? क्या डाटाबेस से मूल्य पढ़ने के लिए कोई बेहतर/क्लीनर/कुशल/मुहावराला गोलांग तरीका है?

मुझे यह विश्वास करना मुश्किल लगता है कि गो जैसे आधुनिक भाषा डेटाबेस रिटर्न को अच्छी तरह से संभाल नहीं पाएगी।

अग्रिम धन्यवाद!

कोड स्निपेट:

// DB read format 
type udInfoBytes struct { 
    id      []byte 
    state     []byte 
} 

// output format 
type udInfo struct { 
    id      string 
    state     string 
} 

func CToGoString(c []byte) string { 
    n := -1 
    for i, b := range c { 
    if b == 0 { 
     break 
    } 
    n = i 
    } 
    return string(c[:n+1]) 
} 

func dbBytesToString(in udInfoBytes) udInfo { 

    var out udInfo 
    var s string 
    var t int 

    out.id = CToGoString(in.id) 
    out.state = stateName(in.state) 
    return out 
} 

func GetInfo(ud string) udInfo { 

    db := getFileHandle() 
    q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud) 

    rows, err := db.Query(q) 
    if err != nil { 
    log.Fatal(err) 
    } 
    defer rows.Close() 
    ret := udInfo{} 
    r := udInfoBytes{} 
    for rows.Next() { 
    err := rows.Scan(&r.id, &r.state) 

    if err != nil { 
     log.Println(err) 
    } 
    break 
    } 
    err = rows.Err() 
    if err != nil { 
    log.Fatal(err) 
    } 

    ret = dbBytesToString(r) 
    defer db.Close() 
    return ret 
} 

संपादित करें:

मैं जहाँ मैं कोई शून्य से निपटने के बारे में चिंता और उन्हें स्वचालित रूप से के रूप में रिक्त स्ट्रिंग को पढ़ने के लिए निम्न कार्य की तरह कुछ करना चाहते हैं।

// output format 
type udInfo struct { 
    id      string 
    state     string 
} 

func GetInfo(ud string) udInfo { 

    db := getFileHandle() 
    q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud) 

    rows, err := db.Query(q) 
    if err != nil { 
    log.Fatal(err) 
    } 
    defer rows.Close() 
    r := udInfo{} 

    for rows.Next() { 
    err := rows.Scan(&r.id, &r.state) 

    if err != nil { 
     log.Println(err) 
    } 
    break 
    } 
    err = rows.Err() 
    if err != nil { 
    log.Fatal(err) 
    } 

    defer db.Close() 
    return r 
} 
+0

उत्तर के लिए धन्यवाद। मैं देखता हूं कि अधिकांश समाधान sql.NullString या डेटाबेस विशिष्ट लाइब्रेरी का उपयोग करने का सुझाव देते हैं। मेरी इच्छा थी कि कुछ सामान्य था जो "डेटाबेस/एसक्यूएल" पर चलाएगा। उस समय के लिए मैं sql.NullString समाधान का उपयोग करूंगा क्योंकि मुझे ओडीबीसी (मुझे पता है, दर्दनाक) के माध्यम से एक दूरस्थ sqlserver डेटाबेस से कनेक्ट करना है। – FlowRaja

उत्तर

19

अलग प्रकार null डेटाबेस से आ रही मानों का प्रबंधन कैसे कर रहे हैं इस तरह के sql.NullBool, sql.NullFloat64, आदि

उदाहरण के लिए के रूप में: के

var s sql.NullString 
err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) 
... 
if s.Valid { 
    // use s.String 
} else { 
    // NULL value 
} 
+0

यह अभी भी एक प्रकार से दूसरे में कॉपी करने की मेरी परेशानी को रोकता नहीं है। जिस तरह से मैं इसे 25+ मानों में से प्रत्येक के लिए देखता हूं, मुझे नलस्ट्रिंग प्रकार से स्ट्रिंग प्रकार में कॉपी करना होगा। हालांकि, यह मुझे कार्यों से छुटकारा पाने में मदद करता है, जिसका स्वागत है। तो इसके लिए आपका शुक्रिया। – FlowRaja

+1

हां, आपको शून्य मानों को संभालना होगा। आपके विशेष मामले में, आप इसके लिए कुछ रैपर लिख सकते हैं। साथ ही, आपको उपयोगी https://github.com/jmoiron/sqlx पैकेज मिल सकता है, जो आपके कार्य को सरल बना सकता है। – divan

8

जाने के डेटाबेस/एसक्यूएल पैकेज संभाल सूचक प्रकार।

package main 

import (
    "database/sql" 
    "fmt" 
    _ "github.com/mattn/go-sqlite3" 
    "log" 
) 

func main() { 
    db, err := sql.Open("sqlite3", ":memory:") 
    if err != nil { 
     log.Fatal(err) 
    } 
    defer db.Close() 

    _, err = db.Exec("create table foo(id integer primary key, value text)") 
    if err != nil { 
     log.Fatal(err) 
    } 
    _, err = db.Exec("insert into foo(value) values(null)") 
    if err != nil { 
     log.Fatal(err) 
    } 
    _, err = db.Exec("insert into foo(value) values('bar')") 
    if err != nil { 
     log.Fatal(err) 
    } 
    rows, err := db.Query("select id, value from foo") 
    if err != nil { 
     log.Fatal(err) 
    } 
    for rows.Next() { 
     var id int 
     var value *string 
     err = rows.Scan(&id, &value) 
     if err != nil { 
      log.Fatal(err) 
     } 
     if value != nil { 
      fmt.Println(id, *value) 
     } else { 
      fmt.Println(id, value) 
     } 
    } 
} 

आप नीचे दिए गए की तरह मिलना चाहिए:

1 <nil> 
2 bar 
-2

मैं के रूप में यह एसटीडी पुस्तकालय की है कि एक अच्छे इंटरफ़ेस का उपयोग करता MyMySql ड्राइवर का उपयोग करने के लिए शुरू कर दिया है।

https://github.com/ziutek/mymysql

मैं तो साधारण डेटाबेस की क्वेरी लपेटा गया है कार्यों का उपयोग करने के लिए।

import "github.com/ziutek/mymysql/mysql" 
import _ "github.com/ziutek/mymysql/native" 

// Execute a prepared statement expecting multiple results. 
func Query(sql string, params ...interface{}) (rows []mysql.Row, err error) { 
    statement, err := db.Prepare(sql) 
    if err != nil { 
     return 
    } 
    result, err := statement.Run(params...) 
    if err != nil { 
     return 
    } 
    rows, err = result.GetRows() 
    return 
} 

इस इस स्निपेट के रूप में सरल है उपयोग करने के लिए:

rows, err := Query("SELECT * FROM table WHERE column = ?", param) 

for _, row := range rows { 
    column1 = row.Str(0) 
    column2 = row.Int(1) 
    column3 = row.Bool(2) 
    column4 = row.Date(3) 
    // etc... 
} 

सूचना एक विशेष मूल्य के लिए मजबूर करने के लिए अच्छा पंक्ति तरीकों यह एक ऐसा कार्य है। Nulls पुस्तकालय द्वारा नियंत्रित किया जाता है और नियमों यहाँ प्रलेखित रहे हैं:

https://github.com/ziutek/mymysql/blob/master/mysql/row.go

1

एक वैकल्पिक समाधान COALESCE समारोह (सभी नहीं डीबी के इस समर्थन कर सकते हैं, हालांकि) का उपयोग करके SQL विवरण अपने आप में इस संभाल करने के लिए किया जाएगा।

उदाहरण के लिए आप के बजाय इस्तेमाल कर सकते हैं:

q := fmt.Sprintf("SELECT id,COALESCE(state, '') as state FROM Mytable WHERE id='%s' ", ud) 

जो प्रभावी रूप से 'राज्य' घटना में कोई रिक्त स्ट्रिंग का डिफ़ॉल्ट मान है कि यह DB में एक शून्य के रूप में जमा हो गया था देना होगा।

संबंधित मुद्दे