Question

I have some tables in Postgres like this.

create table foo (
    txt text
);
insert into foo (txt) values ('a');
insert into foo (txt) values ('b');
insert into foo (txt) values ('c');

create table bar (
  txt text,
  n integer not null unique
);

I'm doing a schema migration. I would like to migrate data from foo to bar. I'd like bar to look like this.

=# select * from new;
txt | n
----+--
a   | 1
b   | 2
c   | 3

n doesn't have to be sequential, but it does have to be unique and not null.

I thought this query would work.

insert into bar (txt, n)
select txt, generate_series(1, (select count(*) from foo))
from foo;

But I think that's generating rows 1-N over and over again for each 'a', 'b', 'c', which violates the unique constraint.

SQL Fiddle: http://sqlfiddle.com/#!17/06e92c


Update

Okay, I found one hacky way to do it.

insert into bar (txt, n)
select txt, trunc(random() * 999999 + 1)
from foo;

Of course this isn't guaranteed to be unique. :/ But, if the data set is small enough, you might be able to scrape by with this.

Also, I understand why the first approach failed now. generate_series returns multiple rows, whereas with random I only return 1 row.

Était-ce utile?

La solution

Why not use row_number()

insert into bar (txt, n)
select txt, row_number() over ()
from foo;

I left out an order by which would slow down the query and wouldn't really be an advantage in your case as you just want a unique number.

An alternative would be to create a sequence for it, if the performance of the window function isn't sufficient.

create sequence seq_foo_nr;

insert into bar (txt, n)
select txt, nextval('seq_foo_nr')
from foo;

drop sequence seq_foo_nr;

If you need an auto-generated number anyway, then define nr as an identity column:

create table bar (
  txt text,
  n integer not null unique generated always as identity
);

insert into bar (txt)
select txt
from foo;
Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top