第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問題,去搜搜看,總會(huì)有你想問的

Golang 結(jié)構(gòu)的 Postgres 數(shù)組

Golang 結(jié)構(gòu)的 Postgres 數(shù)組

Go
躍然一笑 2022-06-01 16:02:52
我有以下 Go 結(jié)構(gòu):type Bar struct {    Stuff string `db:"stuff"`    Other string `db:"other"`}type Foo struct {    ID    int    `db:"id"`    Bars  []*Bar `db:"bars"`}所以Foo包含一片Bar指針。我在 Postgres 中也有以下表格:CREATE TABLE foo (    id  INT)CREATE TABLE bar (    id      INT,    stuff   VARCHAR,    other   VARCHAR,    trash   VARCHAR)我想LEFT JOIN放在桌子上bar并將其聚合為要存儲(chǔ)在 struct 中的數(shù)組Foo。我試過了:SELECT f.*,ARRAY_AGG(b.stuff, b.other) AS barsFROM foo fLEFT JOIN bar bON f.id = b.idWHERE f.id = $1GROUP BY f.id但看起來ARRAY_AGG函數(shù)簽名不正確(function array_agg(character varying, character varying) does not exist)。有沒有辦法在不單獨(dú)查詢的情況下做到這一點(diǎn)bar?
查看完整描述

2 回答

?
繁星點(diǎn)點(diǎn)滴滴

TA貢獻(xiàn)1803條經(jīng)驗(yàn) 獲得超3個(gè)贊

看起來你想要的是bars一個(gè) bar 對(duì)象數(shù)組來匹配你的 Go 類型。為此,您應(yīng)該使用JSON_AGG而不是ARRAY_AGG因?yàn)锳RRAY_AGG僅適用于單列,并且在這種情況下會(huì)生成文本類型 ( TEXT[]) 的數(shù)組。JSON_AGG,另一方面,創(chuàng)建一個(gè) json 對(duì)象數(shù)組。您可以將其與JSON_BUILD_OBJECT僅選擇所需的列相結(jié)合。


這是一個(gè)例子:


SELECT f.*,

JSON_AGG(JSON_BUILD_OBJECT('stuff', b.stuff, 'other', b.other)) AS bars

FROM foo f

LEFT JOIN bar b

ON f.id = b.id

WHERE f.id = $1

GROUP BY f.id

然后你必須處理在 Go 中解組 json,但除此之外你應(yīng)該很高興。


另請(qǐng)注意,在將 json 解組為結(jié)構(gòu)時(shí),Go 會(huì)為您忽略未使用的鍵,因此您可以根據(jù)bar需要選擇表上的所有字段來簡化查詢。像這樣:


SELECT f.*,

JSON_AGG(TO_JSON(b.*)) AS bars -- or JSON_AGG(b.*)

FROM foo f

LEFT JOIN bar b

ON f.id = b.id

WHERE f.id = $1

GROUP BY f.id

如果您還想處理 inbar中的記錄沒有條目的情況foo,您可以使用:


SELECT f.*,

COALESCE(

    JSON_AGG(TO_JSON(b.*)) FILTER (WHERE b.id IS NOT NULL),

    '[]'::JSON

) AS bars

FROM foo f

LEFT JOIN bar b

ON f.id = b.id

WHERE f.id = $1

GROUP BY f.id

如果沒有FILTER,您將獲得[NULL]infoo中沒有相應(yīng)行的行bar,而FILTER只是給您NULL,然后只需使用它COALESCE來轉(zhuǎn)換為空的 json 數(shù)組。


查看完整回答
反對(duì) 回復(fù) 2022-06-01
?
鳳凰求蠱

TA貢獻(xiàn)1825條經(jīng)驗(yàn) 獲得超4個(gè)贊

正如您已經(jīng)知道的那樣array_agg,接受一個(gè)參數(shù)并返回參數(shù)類型的數(shù)組。因此,如果您希望所有行的列都包含在數(shù)組的元素中,您可以直接傳入行引用,例如:


SELECT array_agg(b) FROM b

但是,如果您只想在數(shù)組元素中包含特定列,則可以使用ROW構(gòu)造函數(shù),例如:


SELECT array_agg(ROW(b.stuff, b.other)) FROM b

Go 的標(biāo)準(zhǔn)庫為僅掃描標(biāo)量值提供了開箱即用的支持。要掃描更復(fù)雜的值,例如任意對(duì)象和數(shù)組,必須尋找 3rd 方解決方案,或者實(shí)現(xiàn)他們自己的sql.Scanner.


為了能夠?qū)崿F(xiàn)自己的sql.Scanner并正確解析 postgres 行數(shù)組,您首先需要知道 postgres 用于輸出值的格式,您可以通過使用psql和一些直接查詢來找到它:


-- simple values

SELECT ARRAY[ROW(123,'foo'),ROW(456,'bar')];

-- output: {"(123,foo)","(456,bar)"}


-- not so simple values 

SELECT ARRAY[ROW(1,'a b'),ROW(2,'a,b'),ROW(3,'a",b'),ROW(4,'(a,b)'),ROW(5,'"','""')];

-- output: {"(1,\"a b\")","(2,\"a,b\")","(3,\"a\"\",b\")","(4,\"(a,b)\")","(5,\"\"\"\",\"\"\"\"\"\")"}

正如你所看到的,這可能會(huì)變得很復(fù)雜,但它是可解析的,語法看起來是這樣的:


{"(column_value[, ...])"[, ...]}

wherecolumn_value是未加引號(hào)的值,或者是帶有轉(zhuǎn)義雙引號(hào)的引用值,并且這樣的引用值本身可以包含轉(zhuǎn)義的雙引號(hào),但只能包含兩個(gè),即單個(gè)轉(zhuǎn)義的雙引號(hào)不會(huì)出現(xiàn)在column_value. 所以解析器的粗略和不完整的實(shí)現(xiàn)可能看起來像這樣:


注意:在解析過程中可能需要考慮其他我不知道的語法規(guī)則。除此之外,下面的代碼不能正確處理 NULL。


func parseRowArray(a []byte) (out [][]string) {

    a = a[1 : len(a)-1] // drop surrounding curlies


    for i := 0; i < len(a); i++ {

        if a[i] == '"' { // start of row element

            row := []string{}


            i += 2 // skip over current '"' and the following '('

            for j := i; j < len(a); j++ {

                if a[j] == '\\' && a[j+1] == '"' { // start of quoted column value

                    var col string // column value


                    j += 2 // skip over current '\' and following '"'

                    for k := j; k < len(a); k++ {

                        if a[k] == '\\' && a[k+1] == '"' { // end of quoted column, maybe

                            if a[k+2] == '\\' && a[k+3] == '"' { // nope, just escaped quote

                                col += string(a[j:k]) + `"`

                                k += 3    // skip over `\"\` (the k++ in the for statement will skip over the `"`)

                                j = k + 1 // skip over `\"\"`

                                continue  // go to k loop

                            } else { // yes, end of quoted column

                                col += string(a[j:k])

                                row = append(row, col)

                                j = k + 2 // skip over `\"`

                                break     // go back to j loop

                            }

                        }


                    }


                    if a[j] == ')' { // row end

                        out = append(out, row)

                        i = j + 1 // advance i to j's position and skip the potential ','

                        break     // go to back i loop

                    }

                } else { // assume non quoted column value

                    for k := j; k < len(a); k++ {

                        if a[k] == ',' || a[k] == ')' { // column value end

                            col := string(a[j:k])

                            row = append(row, col)

                            j = k // advance j to k's position

                            break // go back to j loop

                        }

                    }


                    if a[j] == ')' { // row end

                        out = append(out, row)

                        i = j + 1 // advance i to j's position and skip the potential ','

                        break     // go to back i loop

                    }

                }

            }

        }

    }

    return out

}

試一試playground。


有了類似的東西,您就可sql.Scanner以為您的 Go 條形圖實(shí)現(xiàn)一個(gè)。


type BarList []*Bar


func (ls *BarList) Scan(src interface{}) error {

    switch data := src.(type) {

    case []byte:

        a := praseRowArray(data)

        res := make(BarList, len(a))

        for i := 0; i < len(a); i++ {

            bar := new(Bar)

            // Here i'm assuming the parser produced a slice of at least two

            // strings, if there are cases where this may not be the true you

            // should add proper length checks to avoid unnecessary panics.

            bar.Stuff = a[i][0]

            bar.Other = a[i][1]

            res[i] = bar

        }

        *ls = res

    }

    return nil

}

現(xiàn)在,如果您將類型中的Bars字段Foo類型從[]*Bar更改為,BarList您將能夠直接將字段的指針傳遞給(*sql.Row|*sql.Rows).Scan調(diào)用:


rows.Scan(&f.Bars)

如果您不想更改字段的類型,您仍然可以通過在將指針傳遞給Scan方法時(shí)轉(zhuǎn)換指針來使其工作:


rows.Scan((*BarList)(&f.Bars))

JSON

sql.ScannerHenry Woody 建議的 json 解決方案的實(shí)現(xiàn)如下所示:


type BarList []*Bar


func (ls *BarList) Scan(src interface{}) error {

    if b, ok := src.([]byte); ok {

        return json.Unmarshal(b, ls)

    }

    return nil

}


查看完整回答
反對(duì) 回復(fù) 2022-06-01
  • 2 回答
  • 0 關(guān)注
  • 235 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)