文字列の配列を含む単一の列を持つ行を返すクエリがあります(character varying[]
):
{http://wp.me/p62MJv-Jc,http://tyrant.click/1LGBoD6}
これをGolangスライスに直接読み取る簡単な方法はありますか?例えば。
var arr []string
for rows.Next() {
rows.Scan(&arr)
fmt.Println(len(arr))
}
生産:
0
元の投稿のコメントでVictorが述べたように、 this 投稿は、pq.Array()
の説明で質問にうまく答えます。
リンクから直接取得:
Postgres配列値をGoスライスに読み込むには、次を使用します。
func getTags(db *sql.DB, title string) (tags []string) { // the select query, returning 1 column of array type sel := "SELECT tags FROM posts WHERE title=$1" // wrap the output parameter in pq.Array for receiving into it if err := db.QueryRow(sel, title).Scan(pq.Array(&tags)); err != nil { log.Fatal(err) } return }
私自身のプロジェクトでもこれが機能しているので、機能することを確認できます。
私はこれが仕事をするべきだと思います。 SQLでarray_to_jsonを使用します。次にnmarshalling 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))
}
現時点では、lib/pq
ライブラリを使用してPostgreSQL配列をGoスライスにロードする直接的な方法はありません。ある時点かもしれませんが、そのようなことを図書館自体が透過的に処理すべきかどうかについては、いくつかの議論がありました。
ただし、1つのオプションは、結果を文字列({item1,item2,"comma,item"}
のように見える)にロードし、以下のコードで行われるように、正規表現を使用してその文字列を文字列スライスに分割することです(一部は-から取得) この要点 Andrew Harrisによる):
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
}
使用方法は次のとおりです。
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)
}
データベースには次のものがあります。
# \d links
Table "public.links"
Column | Type | Modifiers
--------+--------+-----------
link | text[] |
# select * from links;
link
------------------------------
{this,that}
{another,thing}
{}
{"test,123","one,two,three"}
(5 rows)
これは、上記のGoコードによって出力されるものです。
2 []string{"this,", "that"}
2 []string{"another,", "thing"}
2 []string{"another,", "thing"}
0 []string{}
2 []string{"test,123\",", "one,two,three"}
このコードのバリエーションはあちこちで見られますが、特定のテストセットでは機能しません。
ここに、私が投げたすべてのテスト値を処理するものを書きました(テストケースが続きます)。また、約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{" ",""}},
}