2013-07-28 3 views
11

Теперь я использую вручную разобрать JSON в вставить строку, как такPostgreSQL: вставить данные в таблицу из JSON

insert into Table (field1, field2) values (val1, val2) 

, но его не удобный способ вставки данных из JSON! Я нашел функцию json_populate_record и пытался использовать его:

create table test (id serial, name varchar(50)); 
insert into test select * from json_populate_record(NULL::test, '{"name": "John"}'); 

но он терпит неудачу с сообщением: пустое значение в столбце «ид» нарушает не-нулевое ограничение PG знает, что идентификатор серийный, но притворяется дурак. То же самое и для всех фидов с дефолтами.

Есть ли более элегантный способ вставить данные из json в таблицу?

+1

"Я нашел функцию' json_populate_record'. Um. *Где*? Что такое определение функции? Вы используете бета-версию PostgreSQL 9.3, или это функция, которую вы установили из другого места? –

+0

Это 9,3 бета функция – user2627000

ответ

10

Для json_populate_record нет простого способа вернуть маркер, что означает «сгенерировать это значение».

PostgreSQL делает не Позволяет вам вставить NULL, чтобы указать, что значение должно быть сгенерировано. Если вы попросите NULL Pg ожидает означаетNULL и не хочет вас укусить. Кроме того, вполне нормально иметь сгенерированный столбец, который не имеет ограничения NOT NULL, и в этом случае отлично вставить в него NULL.

Если вы хотите, чтобы PostgreSQL использовать таблицу по умолчанию для значения Есть два способа сделать это:

  • Omit, что строка из INSERT-столбца списка; или
  • Явное написать DEFAULT, который действителен только в выражении VALUES

Поскольку вы не можете использовать VALUES(DEFAULT, ...) здесь, ваш единственный вариант, чтобы пропустить столбец из INSERT колонного списка:

regress=# create table test (id serial primary key, name varchar(50)); 
CREATE TABLE 
regress=# insert into test(name) select name from json_populate_record(NULL::test, '{"name": "John"}'); 
INSERT 0 1 

Да, это означает, что вы должны указать столбцы. Дважды, фактически, один раз в списке SELECT и один раз в списке столбцов INSERT.

Чтобы избежать необходимости, что PostgreSQL будет необходимо иметь способ определения DEFAULT в качестве значения для записи, так json_populate_record может вернуться DEFAULT вместо NULL для столбцов, которые не определены. Возможно, это не так, как вы планировали для всех столбцов, и это привело бы к вопросу о том, как обрабатывать DEFAULT, когда json_populate_record был , а не, который используется в выражении INSERT.

Поэтому я думаю, json_populate_record может быть менее полезным, чем вы надеялись на строки с сгенерированными ключами.

+0

очень круто. есть ли способ «ОБНОВИТЬ» тоже, на основе ввода json? – jney

+0

@jney Я не совсем уверен, что вы просите. Я предлагаю опубликовать новый подробный вопрос и связать его с контекстом. –

+0

Очень полезная информация (документация для 'json_populate_record' немного разрежена). Но действительно кажется, что это хороший случай для опции эффекта «где не указано значение, используйте значение по умолчанию». – beldaz

6

Продолжая Craig's answer, вы, вероятно, нужно написать какой-то хранимой процедуры для выполнения необходимых динамического SQL, как выглядит следующим образом:

CREATE OR REPLACE FUNCTION jsoninsert(relname text, reljson text) 
    RETURNS record AS 
$BODY$DECLARE 
ret RECORD; 
inputstring text; 
BEGIN 
    SELECT string_agg(quote_ident(key),',') INTO inputstring 
    FROM json_object_keys(reljson::json) AS X (key); 
    EXECUTE 'INSERT INTO '|| quote_ident(relname) 
    || '(' || inputstring || ') SELECT ' || inputstring 
    || ' FROM json_populate_record(NULL::' || quote_ident(relname) || ' , json_in($1)) RETURNING *' 
    INTO ret USING reljson::cstring; 
    RETURN ret; 
END; 
$BODY$ 
LANGUAGE plpgsql VOLATILE; 

Что вы тогда звоните с

SELECT jsoninsert('test', '{"name": "John"}');