2015-05-27 8 views
7

में सीधे एक Postgresql सरणी पढ़ें मैं है एक प्रश्न जो तार की एक सरणी (character varying[]) युक्त एक एकल स्तंभ के साथ एक पंक्ति रिटर्न:एक Golang स्लाइस

{http://wp.me/p62MJv-Jc,http://tyrant.click/1LGBoD6} 

कोई आसान तरीका सीधे में इस पढ़ने के लिए है एक गोलांग टुकड़ा? जैसे

var arr []string 

for rows.Next() { 
    rows.Scan(&arr) 
    fmt.Println(len(arr)) 
} 

का उत्पादन:

0 
+1

कौन सा PostgreSQL डेटाबेस ड्राइवर आप उपयोग कर रहे हैं? क्या आपने इसके दस्तावेज के माध्यम से पढ़ा था (ऐसी सुविधा ड्राइवर द्वारा प्रदान की जाएगी)? ऐसा विफल होने पर, आप शायद एक टुकड़ा प्रकार बना सकते हैं जो ['sql.Scanner'] लागू करता है (https://golang.org/pkg/database/sql/#Scanner)। –

+0

http://godoc.org/github.com/lib/pq का उपयोग करना ठीक है धन्यवाद, मैं उसमें देखता हूं, यह निराशाजनक है कि यह बॉक्स –

+0

बीटीडब्लू के बाहर उपलब्ध नहीं है, आपको 'लेन (एआर)' 'स्कैन' से त्रुटि वापसी की जांच किए बिना (जो संभवतः कुछ ऐसा होगा: "प्रतिबिंबित करें। सेट: प्रकार का मान [] uint8 टाइप करने के लिए असाइन करने योग्य नहीं है [] स्ट्रिंग", यानी डेटाबेस ड्राइवर को कॉलम को '[] byte')। –

उत्तर

7

मुझे लगता है कि यह काम करना चाहिए। एसक्यूएल में array_to_json का उपयोग करना। तब unmarshalling json स्ट्रिंग टुकड़ा golang को

sql-> select array_to_json(arr) from .... 

var arrStr string 
var arr []string 

for rows.Next() { 
    rows.Scan(&arrStr) 
    json.Unmarshal([]byte(arrStr), &arr) 
    fmt.Println(len(arr)) 
} 
2

फिलहाल, वहाँ एक जाओ टुकड़ा lib/pq लाइब्रेरी का उपयोग कर में एक PostgreSQL सरणी लोड करने के लिए कोई सीधा रास्ता है। यह किसी बिंदु पर हो सकता है, लेकिन इस पर कुछ बहस हुई है कि पुस्तकालय द्वारा ऐसी चीज को पारदर्शी रूप से संभाला जाना चाहिए या नहीं।

हालांकि, एक विकल्प (कि {item1,item2,"comma,item"} तरह दिखता है) एक स्ट्रिंग में परिणाम लोड करने के लिए, और फिर एक स्ट्रिंग टुकड़ा में है कि स्ट्रिंग विभाजित रेगुलर एक्सप्रेशन के उपयोग, के रूप में नीचे दिए गए कोड (द्वारा this Gist से हिस्से में ले जाया में किया है एंड्रयू हैरिस):

:

rows, err := db.Query("SELECT link FROM links") 
if err != nil { 
    panic(err) 
} 
var tmp string 
for rows.Next() { 
    rows.Scan(&tmp) 
    links := pgArrayToSlice(tmp) 
    fmt.Println(len(links), links) 
} 
डेटाबेस में निम्नलिखित के साथ

:

import (
    "regexp" 
    "strings" 
) 

var (
    // unquoted array values must not contain: (" , \ { } whitespace NULL) 
    // and must be at least one char 
    unquotedChar = `[^",\\{}\s(NULL)]` 
    unquotedValue = fmt.Sprintf("(%s)+", unquotedChar) 

    // quoted array values are surrounded by double quotes, can be any 
    // character except " or \, which must be backslash escaped: 
    quotedChar = `[^"\\]|\\"|\\\\` 
    quotedValue = fmt.Sprintf("\"(%s)*\"", quotedChar) 

    // an array value may be either quoted or unquoted: 
    arrayValue = fmt.Sprintf("(?P<value>(%s|%s))", unquotedValue, quotedValue) 

    // Array values are separated with a comma IF there is more than one value: 
    arrayExp = regexp.MustCompile(fmt.Sprintf("((%s)(,)?)", arrayValue)) 
) 

// Parse the output string from the array type. 
// Regex used: (((?P<value>(([^",\\{}\s(NULL)])+|"([^"\\]|\\"|\\\\)*")))(,)?) 
func pgArrayToSlice(array string) []string { 
    var valueIndex int 
    results := make([]string, 0) 
    matches := arrayExp.FindAllStringSubmatch(array, -1) 
    for _, match := range matches { 
     s := match[valueIndex] 
     // the string _might_ be wrapped in quotes, so trim them: 
     s = strings.Trim(s, "\"") 
     results = append(results, s) 
    } 
    return results 
} 

यह इस प्रकार से इस्तेमाल किया जा सकता है

यह ऊपर जाओ कोड से उत्पादन होता है क्या है:

2 []string{"this,", "that"} 
2 []string{"another,", "thing"} 
2 []string{"another,", "thing"} 
0 []string{} 
2 []string{"test,123\",", "one,two,three"} 
1

मैं हर जगह इस कोड के रूपांतरों देखा है, लेकिन यह कुछ परीक्षण सेट के लिए मेरे लिए काम नहीं करता।

यहां कुछ लिखा है जो मैंने लिखा है कि सभी टेस्ट वैल्यू जो मैंने फेंक दिया है (परीक्षण के मामलों का पालन करें)। यह लगभग 80% तेज है।

func ParsePGArray(array string) ([]string, error) { 
    var out []string 
    var arrayOpened,quoteOpened,escapeOpened bool 
    item := &bytes.Buffer{} 
    for _, r := range array { 
    switch { 
    case !arrayOpened: 
     if r != '{' { 
     return nil, errors.New("Doesn't appear to be a postgres array. Doesn't start with an opening curly brace.") 
     } 
     arrayOpened = true 
    case escapeOpened: 
     item.WriteRune(r) 
     escapeOpened = false 
    case quoteOpened: 
     switch r { 
     case '\\': 
     escapeOpened = true 
     case '"': 
     quoteOpened = false 
     if item.String() == "NULL" { 
      item.Reset() 
     } 
     default: 
     item.WriteRune(r) 
     } 
    case r == '}': 
     // done 
     out = append(out, item.String()) 
     return out, nil 
    case r == '"': 
     quoteOpened = true 
    case r == ',': 
     // end of item 
     out = append(out, item.String()) 
     item.Reset() 
    default: 
     item.WriteRune(r) 
    } 
    } 
    return nil, errors.New("Doesn't appear to be a postgres array. Premature end of string.") 
} 

यहाँ परीक्षण मामलों रहे हैं:

scanTests := []struct { 
    in string 
    out []string 
}{ 
    {"{one,two}", []string{"one", "two"}}, 
    {`{"one, sdf",two}`, []string{"one, sdf", "two"}}, 
    {`{"\"one\"",two}`, []string{`"one"`, "two"}}, 
    {`{"\\one\\",two}`, []string{`\one\`, "two"}}, 
    {`{"{one}",two}`, []string{`{one}`, "two"}}, 
    {`{"one two"}`, []string{`one two`}}, 
    {`{"one,two"}`, []string{`one,two`}}, 
    {`{abcdef:83bf98cc-fec9-4e77-b4cf-99f9fb6655fa-0NH:zxcvzxc:wers:vxdfw-asdf-asdf}`, []string{"abcdef:83bf98cc-fec9-4e77-b4cf-99f9fb6655fa-0NH:zxcvzxc:wers:vxdfw-asdf-asdf"}}, 
    {`{"",two}`, []string{"","two"}}, 
    {`{" ","NULL"}`, []string{" ",""}}, 
}