j'ai une table appelée livre
CREATE TABLE book
(
id smallint NOT NULL DEFAULT 0,
bname text,
btype text,
bprices numeric(11,2)[],
CONSTRAINT key PRIMARY KEY (id )
)
et une fonction Save_Book
CREATE OR REPLACE FUNCTION save_book(thebook book)
RETURNS text AS
$BODY$
DECLARE
myoutput text :='Nothing has occured';
BEGIN
update book set
bname=thebook.bname,
btype=thebook.btype,bprices=thebook.bprices WHERE id=thebook.id;
IF FOUND THEN
myoutput:= 'Record with PK[' || thebook.id || '] successfully updated';
RETURN myoutput;
END IF;
BEGIN
INSERT INTO book values(thebook.id,thebook.bname,thebook.btype,
thebook.bprices);
myoutput:= 'Record successfully added';
END;
RETURN myoutput;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
maintenant quand j'appelle la fonction
SELECT save_book('(179,the art of war,fiction,{190,220})'::book);
je reçois l'erreur
ERROR: malformed array literal: "{190"
SQL state: 22P02
Character: 18
je ne comprends pas parce que je ne vois aucune erreur dans le format de la matrice, aucune aide?
Ce genre de chose est compliqué. Je travaille actuellement sur certains projets connexes. Le Tweak de base est que PostgreSQL utilise un format qui utilise des guillemets doubles en interne dans la représentation des tuples pour représenter des valeurs littérales, de sorte que:
SELECT save_book('(179,the art of war,fiction,"{190,220}")'::book);
devrait marcher. En substance, une astuce soignée crée un CSV et entourer des identificateurs de tuple ou de matrice. Le gros problème est que vous devez faire face à l'échappement (doubler des citations à tous les niveaux selon les besoins). Voici donc exactement l'équivalent:
SELECT save_book('(179,"the art of war","fiction","{""190"",""220""}")'::book);
La deuxième approche consiste à utiliser un constructeur de ligne:
SELECT save_book(row(179,'the art of war','fiction', array[190,220])::book);
La première solution a l'avantage évident d'être capable de tirer parti des cadres de programmation existants pour la génération de CSV et de l'échappement. La seconde est la plus propre dans SQL. Ils peuvent être mélangés et assortis.
Si vous vous demandez déjà sur la syntaxe correcte pour un type de ligne, posez Postgres. Cela devrait savoir:
SELECT b FROM book b LIMIT 1; -- or: WHERE id = 179;
Qui retournera une représentation de texte de votre ligne au format valide:
(179,"the art of war",fiction,"{190,220}")
Les valeurs des colonnes sont représentées sous la forme d'une liste non cochée et séparée par des virgules, enfermée dans des paréthèses.
Les citations doubles sont utilisées autour des valeurs, s'il peut y avoir une ambiguïté - y compris du texte avec de l'espace blanc. Pendant ce cas particulier, les doubles citations autour de "the art of war"
sont facultatifs, les deux citations autour de "{190,220}"
sont nécessaires pour un tableau.
Joignez la chaîne en guillemets simples, modifiez et testez:
SELECT '(333,the art of war,fiction,"{191,220,235}")'::book
Considérez ce que nous avons discuté sous la question correspondante et précédente:
[.____] problème avec type composite dans une fonction upsert
Un - bloc (BEGIN .. END;
) n'est utile que si vous voulez attraper le EXCEPTION
an INSERT
pourrait soulever. Depuis un bloc avec une exception porte quelques frais généraux, il est logique d'avoir un bloc distinct qui pourrait ne jamais être entré:
CREATE OR REPLACE FUNCTION save_book(thebook book)
RETURNS text AS
$BODY$
BEGIN
UPDATE book
SET bname = thebook.bname
,btype = thebook.btype
,bprices = thebook.bprices
WHERE id = thebook.id;
IF FOUND THEN
RETURN format('Record with PK[%s] successfully updated', thebook.id);
END IF;
BEGIN
INSERT INTO book SELECT (thebook).*;
RETURN format('Record with PK[%s] successfully inserted', thebook.id);
EXCEPTION WHEN unique_violation THEN
UPDATE book
SET bname = thebook.bname
,btype = thebook.btype
,bprices = thebook.bprices
WHERE id = thebook.id;
END;
RETURN format('Record with PK[%s] successfully updated', thebook.id);
END
$BODY$ LANGUAGE plpgsql
Sinon, simplifier :
CREATE OR REPLACE FUNCTION save_book(thebook book)
RETURNS text AS
$BODY$
BEGIN
UPDATE book
SET bname = thebook.bname
,btype = thebook.btype
,bprices = thebook.bprices
WHERE id = thebook.id;
IF FOUND THEN
RETURN format('Record with PK[%s] successfully updated', thebook.id);
END IF;
INSERT INTO book SELECT (thebook).*;
RETURN format('Record with PK[%s] successfully inserted', thebook.id);
END
$BODY$ LANGUAGE plpgsql
J'ai également simplifié votre déclaration INSERT
. Il est prudent d'omettre la liste des colonnes à partir d'insérer dans les circonstances données.
Pendant que je ne vois pas l'avantage réel de votre solution, je veux dire passer une ligne à la fonction au lieu de passer les valeurs individuelles comme dans
CREATE OR REPLACE FUNCTION save_book2(
integer
, text
, text
, integer[]
)
RETURNS text AS
...
Quoi qu'il en soit, votre solution fonctionne également si vous appelez correctement la fonction:
SELECT ave_book((179, 'the art of war', 'fiction', '{190,220}')::book);
C'est-à-dire que l'expression record n'a pas besoin de citer, tandis que les valeurs de texte et le tableau littéral.