Обсуждение: DB design and foreign keys

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

DB design and foreign keys

От
Gianluca Riccardi
Дата:
hello all,
i'm usign PostgreSQL 7.4.7 in a Debian 3.1

following is the SQL schema of my (very)small DB for a (very small)web 
business application:

-- SQL schema for business-test-db

CREATE TABLE customers (  customer_code serial,  alfa_customer_code varchar(6),  customer_name character varying(250)
NOTNULL,  address character varying(250) NOT NULL,  city character varying(250) NOT NULL,  zip_code character
varying(8)NOT NULL,  prov character varying(30) NOT NULL,  security character varying(15) NOT NULL,  tel character
varying(30), tel2 character varying(20) NOT NULL,  fax character varying(250),  url character varying(250),  email1
charactervarying(250) NOT NULL,  email2 character varying(250) NOT NULL,  discount1 integer,  discount2 integer,
PRIMARYKEY (customer_code)
 
);

CREATE TABLE users  (  id smallint NOT NULL,  login varchar(20) NOT NULL,  pwd varchar(20) NOT NULL,  name varchar(20)
NOTNULL,  customer_code int REFERENCES customers (customer_code),  valid date,  primary key (id)
 
);

CREATE TABLE products   (  id serial,  code varchar(60) UNIQUE NOT NULL,  description varchar(250) NOT NULL,
dimensionsvarchar(250) NOT NULL,  price numeric NOT NULL,  state boolean,  PRIMARY KEY (id)
 
);

CREATE TABLE orders  (  id serial,  order_code serial,  customer_code integer REFERENCES customers (customer_code) NOT
NULL, order_date time without time zone NOT NULL,  remote_ip inet NOT NULL,  order_time timestamp with time zone NOT
NULL, order_type varchar(10) NOT NULL,  state varchar(10) NOT NULL,  PRIMARY KEY (id, order_code)
 
);

CREATE TABLE order_items (  id serial,  order_code integer REFERENCES orders (order_code) NOT NULL,  customer_code
integerREFERENCES customers (customer_code) NOT NULL,  product_code varchar(60) REFERENCES products (code) NOT NULL,
qtyint NOT NULL,  price numeric REFERENCES products (price) NOT NULL,  row_price numeric,  PRIMARY KEY (id,
order_code)
);


--
-- END OF FILE

the tables: customers, users, products and orders are created as the SQL 
states.

when i try to create the table order_items postgresql gives the 
following error:

business-test-db=# CREATE TABLE order_items (
business-test-db(#    id serial,
business-test-db(#    order_code integer REFERENCES orders (order_code) 
NOT NULL,
business-test-db(#    customer_code integer REFERENCES customers 
(customer_code) NOT NULL,
business-test-db(#    product_code varchar(60) REFERENCES products 
(code) NOT NULL,
business-test-db(#    qty int NOT NULL,
business-test-db(#    price numeric REFERENCES products (price) NOT NULL,
business-test-db(#    row_price numeric,
business-test-db(#    PRIMARY KEY (id, order_code)
business-test-db(# );
NOTICE:  CREATE TABLE will create implicit sequence "order_items_id_seq" 
for "serial" column "order_items.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 
"order_items_pkey" for table "order_items"
ERROR:  there is no unique constraint matching given keys for referenced 
table "orders"
business-test-db=#


i'm a RTFM man, but i miss the point from the documentation obviously, 
because what i don't understand is why the referenced column isn't 
considered to be unique.
More doubts come into play when i see that the referenced key 
customers(customer_code) by the referencing table orders gives no errors.
I'm not a native english speaker so probably that gives some more 
difficulties.

Thanks in advance to all will contribute a focusing help.

best regards from a proude-to-be postgresql user :-),
Gianluca Riccardi


Re: DB design and foreign keys

От
John McCawley
Дата:
Table orders defines the column order_code as a serial, which simple 
makes a trigger which gives a new value to the column on insert.  Note 
that there is NO guarantee that ths column will be unique.  You can 
manually update the value to whatever you want.  If you wish this column 
to be unique, you must specify it on creation, or later do an alter 
table add constraint to the column.

A foreign key requires that the referenced column be unique (DB 
enforced, not just coincidentally unique), and that' s why your table 
creation is failing.

Gianluca Riccardi wrote:

> hello all,
> i'm usign PostgreSQL 7.4.7 in a Debian 3.1
>
> following is the SQL schema of my (very)small DB for a (very small)web 
> business application:
>
> -- SQL schema for business-test-db
>
> CREATE TABLE customers (
>   customer_code serial,
>   alfa_customer_code varchar(6),
>   customer_name character varying(250) NOT NULL,
>   address character varying(250) NOT NULL,
>   city character varying(250) NOT NULL,
>   zip_code character varying(8) NOT NULL,
>   prov character varying(30) NOT NULL,
>   security character varying(15) NOT NULL,
>   tel character varying(30),
>   tel2 character varying(20) NOT NULL,
>   fax character varying(250),
>   url character varying(250),
>   email1 character varying(250) NOT NULL,
>   email2 character varying(250) NOT NULL,
>   discount1 integer,
>   discount2 integer,
>   PRIMARY KEY (customer_code)
> );
>
> CREATE TABLE users  (
>   id smallint NOT NULL,
>   login varchar(20) NOT NULL,
>   pwd varchar(20) NOT NULL,
>   name varchar(20) NOT NULL,
>   customer_code int REFERENCES customers (customer_code),
>   valid date,
>   primary key (id)
> );
>
> CREATE TABLE products   (
>   id serial,
>   code varchar(60) UNIQUE NOT NULL,
>   description varchar(250) NOT NULL,
>   dimensions varchar(250) NOT NULL,
>   price numeric NOT NULL,
>   state boolean,
>   PRIMARY KEY (id)
> );
>
> CREATE TABLE orders  (
>   id serial,
>   order_code serial,
>   customer_code integer REFERENCES customers (customer_code) NOT NULL,
>   order_date time without time zone NOT NULL,
>   remote_ip inet NOT NULL,
>   order_time timestamp with time zone NOT NULL,
>   order_type varchar(10) NOT NULL,
>   state varchar(10) NOT NULL,
>   PRIMARY KEY (id, order_code)
> );
>
> CREATE TABLE order_items (
>   id serial,
>   order_code integer REFERENCES orders (order_code) NOT NULL,
>   customer_code integer REFERENCES customers (customer_code) NOT NULL,
>   product_code varchar(60) REFERENCES products (code) NOT NULL,
>   qty int NOT NULL,
>   price numeric REFERENCES products (price) NOT NULL,
>   row_price numeric,
>   PRIMARY KEY (id, order_code)
> );
>
>
> -- 
> -- END OF FILE
>
> the tables: customers, users, products and orders are created as the 
> SQL states.
>
> when i try to create the table order_items postgresql gives the 
> following error:
>
> business-test-db=# CREATE TABLE order_items (
> business-test-db(#    id serial,
> business-test-db(#    order_code integer REFERENCES orders 
> (order_code) NOT NULL,
> business-test-db(#    customer_code integer REFERENCES customers 
> (customer_code) NOT NULL,
> business-test-db(#    product_code varchar(60) REFERENCES products 
> (code) NOT NULL,
> business-test-db(#    qty int NOT NULL,
> business-test-db(#    price numeric REFERENCES products (price) NOT NULL,
> business-test-db(#    row_price numeric,
> business-test-db(#    PRIMARY KEY (id, order_code)
> business-test-db(# );
> NOTICE:  CREATE TABLE will create implicit sequence 
> "order_items_id_seq" for "serial" column "order_items.id"
> NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 
> "order_items_pkey" for table "order_items"
> ERROR:  there is no unique constraint matching given keys for 
> referenced table "orders"
> business-test-db=#
>
>
> i'm a RTFM man, but i miss the point from the documentation obviously, 
> because what i don't understand is why the referenced column isn't 
> considered to be unique.
> More doubts come into play when i see that the referenced key 
> customers(customer_code) by the referencing table orders gives no errors.
> I'm not a native english speaker so probably that gives some more 
> difficulties.
>
> Thanks in advance to all will contribute a focusing help.
>
> best regards from a proude-to-be postgresql user :-),
> Gianluca Riccardi
>
> ---------------------------(end of broadcast)---------------------------
> TIP 2: Don't 'kill -9' the postmaster



Re: DB design and foreign keys

От
Tom Lane
Дата:
Gianluca Riccardi <ml-reader@moonwatcher.it> writes:
> CREATE TABLE orders  (
>    id serial,
>    order_code serial,
>    customer_code integer REFERENCES customers (customer_code) NOT NULL,
>    order_date time without time zone NOT NULL,
>    remote_ip inet NOT NULL,
>    order_time timestamp with time zone NOT NULL,
>    order_type varchar(10) NOT NULL,
>    state varchar(10) NOT NULL,
>    PRIMARY KEY (id, order_code)
> );

> when i try to create the table order_items postgresql gives the 
> following error:

> business-test-db=# CREATE TABLE order_items (
> business-test-db(#    id serial,
> business-test-db(#    order_code integer REFERENCES orders (order_code) 
> NOT NULL,
> business-test-db(#    customer_code integer REFERENCES customers 
> (customer_code) NOT NULL,
> business-test-db(#    product_code varchar(60) REFERENCES products 
> (code) NOT NULL,
> business-test-db(#    qty int NOT NULL,
> business-test-db(#    price numeric REFERENCES products (price) NOT NULL,
> business-test-db(#    row_price numeric,
> business-test-db(#    PRIMARY KEY (id, order_code)
> business-test-db(# );
> NOTICE:  CREATE TABLE will create implicit sequence "order_items_id_seq" 
> for "serial" column "order_items.id"
> NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index 
> "order_items_pkey" for table "order_items"
> ERROR:  there is no unique constraint matching given keys for referenced 
> table "orders"

> i'm a RTFM man, but i miss the point from the documentation obviously, 
> because what i don't understand is why the referenced column isn't 
> considered to be unique.

order_code is not by itself unique --- SERIAL doesn't guarantee that.
I'm not sure why you are declaring the primary key of orders as being
the combination of *two* serial columns, but if that's what you really
need and you also want to be able to reference a row by just one of
them, you'll need to apply a separate unique constraint to just the
order_code column.
        regards, tom lane


Re: DB design and foreign keys

От
Jaime Casanova
Дата:
[...unnecesary...]
> CREATE TABLE orders  (
>   id serial,
>   order_code serial,
>   customer_code integer REFERENCES customers (customer_code) NOT NULL,
>   order_date time without time zone NOT NULL,
>   remote_ip inet NOT NULL,
>   order_time timestamp with time zone NOT NULL,
>   order_type varchar(10) NOT NULL,
>   state varchar(10) NOT NULL,
>   PRIMARY KEY (id, order_code)                           ^^^^^^^^^^^^^^^^^^^
> );
[...unnecesary...]
>
> CREATE TABLE order_items (
>   id serial,
>   order_code integer REFERENCES orders (order_code) NOT NULL,
       ^^^^^^^^^^^^^^ 
[...unnecesary...]
> ERROR:  there is no unique constraint matching given keys for referenced
> table "orders"

this is because the PK in the orders table has two fields not one...
so it founds no unique index on orders(order_code)

--
Atentamente,
Jaime Casanova
(DBA: DataBase Aniquilator ;)


Re: DB design and foreign keys

От
Richard Huxton
Дата:
Gianluca Riccardi wrote:
> hello all,
> i'm usign PostgreSQL 7.4.7 in a Debian 3.1
> 

> CREATE TABLE orders  (
>   id serial,
>   order_code serial,
...
>   PRIMARY KEY (id, order_code)
> );
> 
> CREATE TABLE order_items (
>   id serial,
>   order_code integer REFERENCES orders (order_code) NOT NULL,

> when i try to create the table order_items postgresql gives the 
> following error:

> ERROR:  there is no unique constraint matching given keys for referenced 
> table "orders"

It means what it says. You have defined table orders with a primary key 
of (id,order_code). This means that the combination of (id,order_code) 
must be unique. So - these could all exist at the same time: (1,1), (1,2), (2,1), (2,2)
You could not then add another (1,2) combination.

Since id and order_code are both just automatically-generated numbers in 
the orders table it doesn't add anything to make both of them part of a 
primary-key. I would delete the id column altogether and just have the 
order_code as the primary-key (since "order_code" carries more meaning 
to a human than "id"). This means your order_items table can then safely 
reference the order_code it wants to.

HTH
--   Richard Huxton  Archonet Ltd


Re: DB design and foreign keys

От
Scott Marlowe
Дата:
On Tue, 2005-12-13 at 12:16, Gianluca Riccardi wrote:
> hello all,
> i'm usign PostgreSQL 7.4.7 in a Debian 3.1
> 
> following is the SQL schema of my (very)small DB for a (very small)web 
> business application:

> CREATE TABLE orders  (
>    id serial,
>    order_code serial,
>    customer_code integer REFERENCES customers (customer_code) NOT NULL,
>    order_date time without time zone NOT NULL,
>    remote_ip inet NOT NULL,
>    order_time timestamp with time zone NOT NULL,
>    order_type varchar(10) NOT NULL,
>    state varchar(10) NOT NULL,
>    PRIMARY KEY (id, order_code)
> );


Given this table layout, I'm gonna take a wild guess and ask if you're
coming from MySQL and expecting the second serial order_code to be a
sub-autoincrement to id?  If so, it won't be.  That's a mysqlism.  If
you want something similar, you'll have to implement it yourself, and
note that such a thing tends to be a poor performer with lots of
parallel updates, and it can also be susceptible to race conditions if
no locking is used.


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
[cut]

> order_code is not by itself unique --- SERIAL doesn't guarantee that.
>  
>
that was my misunderstanding, i thought (misunderstood) that 'serial' 
implied 'unique'

> I'm not sure why you are declaring the primary key of orders as being
> the combination of *two* serial columns,

i thought it was good design choice and even needed for foreign keys 
referencing on them

> but if that's what you really
> need
>
i'm not shure about that

> and you also want to be able to reference a row by just one of
> them, you'll need to apply a separate unique constraint to just the
> order_code column.
>  
>
sorry, i'm afraid i didn't understand: are you suggesting to apply the 
constraint in case the primary key is kept on the combination of the two 
serial columns? or to remove the primary key of the two serial columns?

>             regards, tom lane
>  
>
thanks a lot for your kind response, best regards,
Gianluca Riccardi


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
John McCawley wrote:

> Table orders defines the column order_code as a serial, which simple 
> makes a trigger which gives a new value to the column on insert.  Note 
> that there is NO guarantee that ths column will be unique.  You can 
> manually update the value to whatever you want.  If you wish this 
> column to be unique, you must specify it on creation, or later do an 
> alter table add constraint to the column.
>
> A foreign key requires that the referenced column be unique (DB 
> enforced, not just coincidentally unique), and that' s why your table 
> creation is failing.


[cut]

that was my misunderstanding

thanks for your reply,
Gianluca Riccardi


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
Jaime Casanova wrote:

> [...unnecesary...]
>  
>
>> CREATE TABLE orders  (
>>  id serial,
>>  order_code serial,
>>  customer_code integer REFERENCES customers (customer_code) NOT NULL,
>>  order_date time without time zone NOT NULL,
>>  remote_ip inet NOT NULL,
>>  order_time timestamp with time zone NOT NULL,
>>  order_type varchar(10) NOT NULL,
>>  state varchar(10) NOT NULL,
>>  PRIMARY KEY (id, order_code)
>>   
>
>                            ^^^^^^^^^^^^^^^^^^^
>  
>
>> );
>>   
>
> [...unnecesary...]
>  
>
>> CREATE TABLE order_items (
>>  id serial,
>>  order_code integer REFERENCES orders (order_code) NOT NULL,
>>   
>
>                                                                  
> ^^^^^^^^^^^^^^
> [...unnecesary...]
>  
>

>> ERROR:  there is no unique constraint matching given keys for referenced
>> table "orders"
>>   
>
>
> this is because the PK in the orders table has two fields not one...
> so it founds no unique index on orders(order_code)
>
>  
>
then, what would you suggest, to remove the primary key from the 'id' 
column? or to remove the 'id' column at all?

>  
>
> -- 
> Atentamente,
> Jaime Casanova
> (DBA: DataBase Aniquilator ;)
>  
>

thank you for your response, regards,
Gianluca Riccardi


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
[cut]

>
> It means what it says. You have defined table orders with a primary 
> key of (id,order_code). This means that the combination of 
> (id,order_code) must be unique. 


yes, that was my thought, and in that context, i thought it could be 
correct in order to have uniqueness for creating foreign keys

> So - these could all exist at the same time:
>  (1,1), (1,2), (2,1), (2,2)
> You could not then add another (1,2) combination.


yes, again, i thought that was the uniqueness i needed...

>
> Since id and order_code are both just automatically-generated numbers 
> in the orders table it doesn't add anything to make both of them part 
> of a primary-key. I would delete the id column altogether and just 
> have the order_code as the primary-key (since "order_code" carries 
> more meaning to a human than "id"). This means your order_items table 
> can then safely reference the order_code it wants to.



> HTH


sure it did, thanks for your response, best regards,
Gianluca Riccardi


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
[cut]

> Given this table layout, I'm gonna take a wild guess and ask if you're
> coming from MySQL and expecting the second serial order_code to be a
> sub-autoincrement to id?
>
no, always used PostgreSQL, but i'm having a deeper approach now, until 
now i've been using th ORDBMS in a very 'easy' manner :(

>  If so, it won't be.  That's a mysqlism.  If
> you want something similar, you'll have to implement it yourself, and
> note that such a thing tends to be a poor performer with lots of
> parallel updates, and it can also be susceptible to race conditions if
> no locking is used.
>  
>
thank you, regards,
Gianluca Riccardi


Re: DB design and foreign keys

От
Gianluca Riccardi
Дата:
so, after the needed modifications the SQL schema is the following

-- SQL schema for business-test-db2

CREATE TABLE customers (  customer_code serial UNIQUE,  alfa_customer_code varchar(6),  customer_name character
varying(250)NOT NULL,  address character varying(250) NOT NULL,  city character varying(250) NOT NULL,  zip_code
charactervarying(8) NOT NULL,  prov character varying(30) NOT NULL,  security character varying(15) NOT NULL,  tel
charactervarying(30),  tel2 character varying(20) NOT NULL,  fax character varying(250),  url character varying(250),
email1character varying(250) NOT NULL,  email2 character varying(250) NOT NULL,  discount1 integer,  discount2 integer,
PRIMARY KEY (customer_code)
 
);

CREATE TABLE users  (  id smallint NOT NULL,  login varchar(20) NOT NULL,  pwd varchar(20) NOT NULL,  name varchar(20)
NOTNULL,  customer_code int REFERENCES customers (customer_code),  valid date,  primary key (id)
 
);

CREATE TABLE products   (  code varchar(60) UNIQUE NOT NULL,  description varchar(250) NOT NULL,  dimensions
varchar(250)NOT NULL,  price numeric NOT NULL,  state boolean,  PRIMARY KEY (code)
 
);

CREATE TABLE orders  (  order_code serial UNIQUE NOT NULL,  customer_code integer REFERENCES customers (customer_code)
NOTNULL,  order_date time without time zone NOT NULL,  remote_ip inet NOT NULL,  order_time timestamp with time zone
NOTNULL,  order_type varchar(10) NOT NULL,  state varchar(10) NOT NULL,  PRIMARY KEY (order_code)
 
);

CREATE TABLE order_items (  order_code integer REFERENCES orders (order_code) NOT NULL,  customer_code integer
REFERENCEScustomers (customer_code) NOT NULL,  product_code varchar(60) REFERENCES products (code) NOT NULL,  qty int
NOTNULL,  price numeric NOT NULL,  row_price numeric
 
);

--
-- END OF FILE

the order_items table is:

business-test-db2=# \d order_items            Tabella "public.order_items"   Colonna         |         Tipo
   | Modificatori
 
-------------------+-------------------------+--------------order_code       | integer                      | not
nullcustomer_code| integer                      | not nullproduct_code   | character varying(60) | not nullqty
       | integer                      | not nullprice                | numeric                    | not nullrow_price
    | numeric                    |
 
Vincoli di integrità referenziale   "$1" FOREIGN KEY (order_code) REFERENCES orders(order_code)   "$2" FOREIGN KEY
(customer_code)REFERENCES customers(customer_code)   "$3" FOREIGN KEY (product_code) REFERENCES products(code)
 

business-test-db2=#



thanks a lot, you all pointed me out of misconceptualized position.

best ragards all,
Gianluca Riccardi

p.s.

Colonna = column
Tipo = type
Modificatori = modifiers
Vincoli di integrita' referenziale = referential integrity constraints