2017-12-03 2 views
1

Ich versuche, eine Zeile mit einer Spalte einzufügen, die ein Array eines benutzerdefinierten Typs (ingredient) ist. Meine Tabellen sind:Einfügen von benutzerdefinierten Typen in Postgres

CREATE TYPE ingredient AS (
    name text, 
    quantity text, 
    unit text 
); 

CREATE TABLE IF NOT EXISTS recipes (
    recipe_id uuid PRIMARY KEY DEFAULT gen_random_uuid(), 
    name text, 
    ingredients ingredient[], 
    // ... 
); 

raw sql ich durch eine Reihe einfügen:

INSERT INTO recipes (name, ingredients) VALUES ('some_name', ARRAY[ROW('aa', 'bb', 'cc'), ROW('xx', 'yy', 'zz')]::ingredient[] );

Aber ich bin zu kämpfen diese mit dem pq lib in gehen zu tun. Ich habe eine pq.Array Schnittstelle erstellt:

type Ingredient struct { 
    Name string 
    Quantity string 
    Unit string 
} 

type Ingredients []*Ingredient 

func (ings *Ingredients) ConvertValue(v interface{}) (driver.Value, error) { 
    return "something", nil 
} 
func (ings *Ingredients) Value() (driver.Value, error) { 
    val := `ARRAY[]` 
    for i, ing := range ings { 
     if i != 0 { 
      val += "," 
     } 
     val += fmt.Printf(`ROW('%v','%v','%v')`, ing.Name, ing.Quantity, ing.Unit) 
    } 
    val += `::ingredient[]` 
    return val, nil 
} 


// and then trying to insert via: 
stmt := `INSERT INTO recipes (
     name, 
     ingredients 
    ) 
    VALUES ($1, $2) 
` 
_, err := db.Exec(stmt, 
    "some_name", 
    &Ingredients{ 
     &Ingredient{"flour", "3", "cups"}, 
    }, 
) 

Aber pg den Fehler immer wieder zu werfen:

Error insertingpq: malformed array literal: "ARRAY[ROW('flour','3','cups')]::ingredient[]" 

Bin ich eine falsche driver.Value Rückkehr?

+0

Haben Sie versucht, die Umwandlung von der 'driver.Value' Weglassen und es auf die Abfrage hinzufügen? z.B. '$ 2 :: Zutaten []'. – mkopriva

+0

Einfach versucht, gleicher Fehler wie oben. –

Antwort

1

Sie entweder diesen Ansatz nutzen können hier skizziert: https://github.com/lib/pq/issues/544

type Ingredient struct { 
    Name string 
    Quantity string 
    Unit string 
} 

func (i *Ingredient) Value() (driver.Value, error) { 
    return fmt.Sprintf("('%s','%s','%s')", i.Name, i.Quantity, i.Unit), nil 
} 

stmt := `INSERT INTO recipes (name, ingredients) VALUES ($1, $2::ingredient[])` 

db.Exec(stmt, "some_name", pq.Array([]*Ingredient{{"flour", "3", "cups"}})) 

Oder wenn Sie Datensätze in der Tabelle, und Sie fragen es, dass Sie wahrscheinlich die Zutat Array in seiner wörtlichen Form sehen, die Sie als während des Einsatzes nachahmen können.

func (ings *Ingredients) Value() (driver.Value, error) { 
    val := `{` 
    for i, ing := range ings { 
     if i != 0 { 
      val += "," 
     } 
     val += fmt.Sprintf(`"('%s','%s','%s')"`, ing.Name, ing.Quantity, ing.Unit) 
    } 
    val += `}` 
    return val, nil 
} 

// e.g. `{"('flour','3','cups')"}` 

stmt := `INSERT INTO recipes (name, ingredients) VALUES ($1, $2::ingredient[])` 

// ... 
+0

Das hat perfekt funktioniert. –

0

Es scheint, dass Ihr Datenbankentwurf sehr kompliziert ist und die Stärken (und Schwächen) von SQL nicht berücksichtigt.

Darf ich vorschlagen, teilen Sie die Zutaten in eine eigene Tabelle mit Bezug auf das Rezept. Dann ist ein JOIN Betrieb herauszufinden, ein komplettes Rezept zu finden.

Erstellen der DB:

CREATE TABLE ingredients (
    recipe_id uuid, 
    name text, 
    quantity int, 
    unit text 
); 

CREATE TABLE recipes (
    recipe_id uuid PRIMARY KEY, 
    name text 
); 

ein Rezept einfügen und Abfragen es vorzulesen:

INSERT INTO recipes VALUES (
    '5d1cb631-37bd-46cc-a278-4c8558ed8964', 'cake1' 
); 

INSERT INTO ingredients (recipe_id, name, quantity, unit) VALUES 
    ('5d1cb631-37bd-46cc-a278-4c8558ed8964', 'flour', 3, 'cups'), 
    ('5d1cb631-37bd-46cc-a278-4c8558ed8964', 'water', 1, 'cups') 
; 

SELECT r.name, i.name, i.quantity, i.unit 
FROM ingredients AS i 
INNER JOIN recipes AS r 
ON r.recipe_id=i.recipe_id; 

SQLFiddle Link: http://sqlfiddle.com/#!17/262ad/14

+0

Ich überlege, dies zu diesem Zeitpunkt zu tun. Der einzige Grund, warum ich nicht vorher war, war, dass ich einfach ein einfaches Array brauchte, ohne auf einzelne Elemente zugreifen oder nach einzelnen Elementen suchen zu müssen. –

Verwandte Themen