Ответ 1
Вы можете использовать функцию окна, чтобы присвоить свои значения SEQ
, например:
INSERT INTO YourTable
(ID, SEQ, DATA)
SELECT ID, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY DATA), DATA
FROM YourSource
Скажем, у меня есть таблица как таковая:
Column | Type | Notes
---------+------------ +----------------------------------------------------------
id | integer | An ID that FK to some other table
seq | integer | Each ID gets its own seq number
data | text | Just some text, totally irrelevant.
id
+ seq
- это комбинированный ключ.
Что я хотел бы увидеть:
ID | SEQ | DATA
----+------ +----------------------------------------------
1 | 1 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
1 | 2 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
1 | 3 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
1 | 4 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
2 | 1 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
3 | 1 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
3 | 2 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
3 | 3 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
3 | 4 | Quick brown fox, lorem ipsum, lazy dog, etc etc.
Как вы можете видеть, комбинация id
и seq
уникальна.
Я не уверен, как настроить мою таблицу (или вставить инструкцию?), чтобы сделать это. Я хотел бы вставить id
и data
, что привело к тому, что seq
была подпоследовательностью, зависящей от id
.
Вы можете использовать функцию окна, чтобы присвоить свои значения SEQ
, например:
INSERT INTO YourTable
(ID, SEQ, DATA)
SELECT ID, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY DATA), DATA
FROM YourSource
Нет проблем! Мы собираемся сделать две таблицы: things
и stuff
. stuff
будет таблицей, которую вы описываете в своем вопросе, а things
- это тот, на который он ссылается:
CREATE TABLE things (
id serial primary key,
name text
);
CREATE TABLE stuff (
id integer references things,
seq integer NOT NULL,
notes text,
primary key (id, seq)
);
Затем мы установим things
с помощью триггера, который будет создавать новую последовательность каждый раз, когда будет создана строка:
CREATE FUNCTION make_thing_seq() RETURNS trigger
LANGUAGE plpgsql
AS $$
begin
execute format('create sequence thing_seq_%s', NEW.id);
return NEW;
end
$$;
CREATE TRIGGER make_thing_seq AFTER INSERT ON things FOR EACH ROW EXECUTE PROCEDURE make_thing_seq();
Теперь мы закончим с thing_seq_1
, thing_seq_2
и т.д. и т.д.
Теперь еще один триггер на stuff
, чтобы он каждый раз использовал правильную последовательность:
CREATE FUNCTION fill_in_stuff_seq() RETURNS trigger
LANGUAGE plpgsql
AS $$
begin
NEW.seq := nextval('thing_seq_' || NEW.id);
RETURN NEW;
end
$$;
CREATE TRIGGER fill_in_stuff_seq BEFORE INSERT ON stuff FOR EACH ROW EXECUTE PROCEDURE fill_in_stuff_seq();
Это гарантирует, что, когда строки войдут в stuff
, столбец id
используется для поиска правильной последовательности для вызова nextval
on.
Здесь демонстрация:
test=# insert into things (name) values ('Joe');
INSERT 0 1
test=# insert into things (name) values ('Bob');
INSERT 0 1
test=# select * from things;
id | name
----+------
1 | Joe
2 | Bob
(2 rows)
test=# \d
List of relations
Schema | Name | Type | Owner
--------+---------------+----------+----------
public | stuff | table | jkominek
public | thing_seq_1 | sequence | jkominek
public | thing_seq_2 | sequence | jkominek
public | things | table | jkominek
public | things_id_seq | sequence | jkominek
(5 rows)
test=# insert into stuff (id, notes) values (1, 'Keychain');
INSERT 0 1
test=# insert into stuff (id, notes) values (1, 'Pet goat');
INSERT 0 1
test=# insert into stuff (id, notes) values (2, 'Family photo');
INSERT 0 1
test=# insert into stuff (id, notes) values (1, 'Redundant lawnmower');
INSERT 0 1
test=# select * from stuff;
id | seq | notes
----+-----+---------------------
1 | 1 | Keychain
1 | 2 | Pet goat
2 | 1 | Family photo
1 | 3 | Redundant lawnmower
(4 rows)
test=#
Если seq
отражает (или должен отражать) порядок, в который вставлены строки, я предпочитаю использовать timestamp
, который автоматически заполняется и генерирует порядковый номер "на лету" при выборе строк с помощью row_number()
:
create table some_table
(
id integer not null,
inserted_at timestamp not null default current_timestamp,
data text
);
Чтобы получить столбец seq
, вы можете сделать:
select id,
row_number() over (partition by id order by inserted_at) as seq,
data
from some_table
order by id, seq;
Выбор будет, однако, немного медленнее по сравнению с использованием сохраненного столбца seq
(особенно с индексом id, seq
).
Если это становится проблемой, вы можете либо изучить использование материализованного представления, либо добавить столбец seq
, а затем обновить его на регулярной основе (я бы не сделал этого в триггере по причинам производительности).
Пример SQLFiddle: http://sqlfiddle.com/#!15/db69b/1
Вы можете использовать Последовательности либо Это также отличный вариант
CREATE SEQUENCE SEQ_NUM START 1;
INSERT INTO TABLE_NAME(ID, SEQ, DATA) VALUES(**SOME_ID**, SELECT nextval('SEQ_NUM') AS SEQ_NUM, **SOME DATA**);
Теперь в этом случае значение Sequence "SEQ_NUM" будет полностью управляться PostgreSQL, теперь вам не нужно управлять никаким счетчиком или чем-либо еще.
Просто догадаться.
INSERT INTO TABLE (ID, SEQ, DATA)
VALUES
(
IDVALUE,
(SELECT max(SEQ) +1 FROM TABLE WHERE ID = IDVALUU),
DATAVALUE
);
Вот простой способ использования стандартного SQL:
INSERT INTO mytable (id, seq, data)
SELECT << your desired ID >>,
COUNT(*) + 1,
'Quick brown fox, lorem ipsum, lazy dog, etc etc.'
FROM mytable
WHERE id = << your desired ID (same as above) >>;
Смотрите SQL Fiddle Demo.
(Если вы хотите быть немного умнее, вы можете подумать о создании trigger, чтобы обновить строку, используя тот же метод сразу после вставить.)
PostgreSQL поддерживает сгруппированные уникальные столбцы:
CREATE TABLE example (
a integer,
b integer,
c integer,
UNIQUE (a, c)
);
См. Документация PostgreSQL - Раздел 5.3.3
Легко: -)
У меня нет никакого опыта postgresql, но можете ли вы использовать подзапрос в своем заявлении insert? Что-то вроде, в Mysqlish,
INSERT INTO MYTABLE SET
ID=4,
SEQ=( SELECT MAX(SEQ)+1 FROM MYTABLE WHERE ID=4 ),
DATA="Quick brown fox, lorem ipsum, lazy dog, etc etc."