Обсуждение: Q: inheritance

Поиск
Список
Период
Сортировка

Q: inheritance

От
Rüdiger Sörensen
Дата:
hi,

I think I misunderstand the concept of inheritance. I was under the
impression that inheriting from an existing table inherits all of the
parent's columns.

But:

create table t1 (id serial primary key);
create table t2 (num int) inherits (t1);
create table t3 (t1 int references t1(id));

insert into t2 (id, num) values (1,1);
-- so far , so good
-- the next one fails:
insert into t3 (t1) values (1);

fails with an error (translated from german):

insert or update in table "t3" violates foreign key constraint "t3_t1_fkey"
DETAIL: key(t1)=(1) is not present in table "t1"

but:

select * from t2;
 id | num
----+-----
  1 |   1

can anyone explain this behaviour? My database setup relies on inherited
tables that share a primary key.

cheers, Rüdiger.





Re: Q: inheritance

От
Richard Huxton
Дата:
Rüdiger Sörensen wrote:
> can anyone explain this behaviour? My database setup relies on inherited
> tables that share a primary key.

I'm afraid inherited tables don't share a primary key. See the manuals
for full details.

--
  Richard Huxton
  Archonet Ltd

Re: Q: inheritance

От
"Richard Broersma"
Дата:
On Thu, Dec 4, 2008 at 8:40 AM, Rüdiger Sörensen
<soerense@mpch-mainz.mpg.de> wrote:

> insert or update in table "t3" violates foreign key constraint "t3_t1_fkey"
> DETAIL: key(t1)=(1) is not present in table "t1"

> select * from t2;
>  id | num
> ----+-----
>  1 |   1

> can anyone explain this behaviour?
Yes,  PostgreSQL table inheritance is really just Horizontal Table
partitioning with a nifty feature that makes the upper node table
behave more like hierarchical UNION ALL views when SELECTed rather
than actual tables.  So in your case, the record you added to t2
doesn't really exits in t1 so referential integrity throws an error in
t3.

> My database setup relies on inherited
> tables that share a primary key.

In this case, I would recommend you use a vertically partitioned table
design that simulates what you are trying to achieve.  I recently
developed a presentation on this subject if you are interested:

http://wiki.postgresql.org/images/9/91/Pguswest2008hnd.pdf

--
Regards,
Richard Broersma Jr.

Visit the Los Angeles PostgreSQL Users Group (LAPUG)
http://pugs.postgresql.org/lapug

Automatic insert statement generator?

От
"Rob Richardson"
Дата:
Greetings!

I was going to make this a question, but I poked around a bit and came
up with an answer, which I'll share here in case anyone else is
interested.

I occasionally need to add test records to a database table.  For
example, I want a new charge that is identical to charge 18000, so I
need coils in inventory that match those in charge 18000:

insert into inventory
select * from inventory where charge = 18000

The problem, of course, is that the inventory table has a unique key
constraint that gets violated.  So, to do this, I'm going to have to
write an insert query that lists every field in this table (all 62 of
them), except for the primary key, which I'll have to force to something
I know is unique.  I would like a database function that would generate
a string that would be a concatenation of all fields in a given table.
Then, I could use the resulting string as the starting point for
building an insert statement that will avoid the key field(s).

So, if I have a table named 'small_table' that contains columns
'column1', 'column2' and 'column3', I would be able to execute:
    SELECT get_fields('small_table')
And I would get back:
    'column1, column2, column3'.

Here's what I did:

-- Function: list_fields("varchar")

-- DROP FUNCTION list_fields("varchar")

CREATE OR REPLACE FUNCTION list_fields("varchar")
  RETURNS "varchar" AS
$BODY$
declare
    Tablename ALIAS for $1;
    Attributes record;
    Result varchar;
begin
    Result := '';
    FOR Attributes IN SELECT attname FROM pg_attribute
              where attrelid = (select oid from pg_class where
relname = Tablename)
              and attstattarget <> 0
    LOOP
    if length(Result) <> 0 then
        Result = Result || ', ';
    end if;
    Result = Result || Attributes.attname;
    END LOOP;

    raise notice '%', Result;
    return Result;

 end;
 $BODY$
  LANGUAGE 'plpgsql' VOLATILE;
ALTER FUNCTION list_fields("varchar") OWNER TO caps;
GRANT EXECUTE ON FUNCTION list_fields("varchar") TO caps;
GRANT EXECUTE ON FUNCTION list_fields("varchar") TO public;


Resp.: Automatic insert statement generator?

От
"Osvaldo Kussama"
Дата:
2008/12/4, Rob Richardson <Rob.Richardson@rad-con.com>:
> ...
> The problem, of course, is that the inventory table has a unique key
> constraint that gets violated.  So, to do this, I'm going to have to
> write an insert query that lists every field in this table (all 62 of
> them), except for the primary key, which I'll have to force to something
> I know is unique.  I would like a database function that would generate
> a string that would be a concatenation of all fields in a given table.
> Then, I could use the resulting string as the starting point for
> building an insert statement that will avoid the key field(s).
>

Try:
CREATE OR REPLACE FUNCTION list_fields(text) RETURNS text AS
$BODY$
-- all attributes names, except those belonging primary key
SELECT array_to_string(
         ARRAY(SELECT pa.attname FROM pg_attribute pa
                                 JOIN pg_class pc ON (pa.attrelid = pc.oid)
                WHERE pc.relname = $1
                  AND pa.attnum > 0
                  AND  pa.attnum <> ALL ((SELECT pco.conkey FROM
pg_constraint pco
                                           WHERE pco.conrelid = pa.attrelid
                                             AND pco.contype =
'p')::smallint[])),
                         ',');
$BODY$
LANGUAGE SQL STABLE;

Osvaldo

Re: Resp.: Automatic insert statement generator?

От
Sebastian Tennant
Дата:
Hi Osvaldo,

Your list_fields function looked interesting to me so I tried it out and
it only worked for one of the five or so tables in the database I was
connected to at the time.

More concerning is the fact that I can't seem to drop it.  I'm told it
doesn't exist, and then I use it to prove (to myself) that it does.


Here's it not working:

 itidb=> select list_fields('joblistings');
 -[ RECORD 1 ]-
 list_fields |

Here's it working:

 itidb=> select list_fields('joblist');
 -[ RECORD 1 ]--------------------------------------------------
 list_fields | full_name,username,password,recruiter,subscribed,...

Here's me trying to drop it, only to be told it doesn't exist:

 itidb=> drop function list_fields();
 ERROR:  function list_fields() does not exist

And here's it working again!

 itidb=> select list_fields('joblist');
 -[ RECORD 1 ]--------------------------------------------------
 list_fields | full_name,username,password,recruiter,subscribed,...


I'm noticing some very strange behaviour this evening (see thread
'Unique constaint violated without being violated').

Is my database corrupted or are there some vital database maintenance
tasks I've neglected to do?

I'm starting to get worried now.

Sebastian

Re: Resp.: Automatic insert statement generator?

От
Raymond O'Donnell
Дата:
On 06/12/2008 16:02, Sebastian Tennant wrote:
> Here's it working:
>
>  itidb=> select list_fields('joblist');

<snip>

> Here's me trying to drop it, only to be told it doesn't exist:
>
>  itidb=> drop function list_fields();
>  ERROR:  function list_fields() does not exist

You need to specify the argument types as well, so this -

  drop function list_fields(varchar); -- or whatever it is

- ought to work.

Ray.

------------------------------------------------------------------
Raymond O'Donnell, Director of Music, Galway Cathedral, Ireland
rod@iol.ie
Galway Cathedral Recitals: http://www.galwaycathedral.org/recitals
------------------------------------------------------------------

Re: Resp.: Automatic insert statement generator?

От
Sebastian Tennant
Дата:
Quoth Raymond O'Donnell <rod@iol.ie>:
> On 06/12/2008 16:02, Sebastian Tennant wrote:
>> Here's it working:
>>
>>  itidb=> select list_fields('joblist');
>
> <snip>
>
>> Here's me trying to drop it, only to be told it doesn't exist:
>>
>>  itidb=> drop function list_fields();
>>  ERROR:  function list_fields() does not exist
>
> You need to specify the argument types as well, so this -
>
>   drop function list_fields(varchar); -- or whatever it is
>
> - ought to work.
>
> Ray.

Man, am I'm feeling geriatric tonight!  Thanks for clearing that up for
me Ray.

I guess this is what comes of working under pressure on a Saturday night
when I should be out having a quiet drink with a few friends.

Sebastian