Обсуждение: Serial data type

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

Serial data type

От
"Christian Rengstl"
Дата:
Hi everyone,

in my Java app at certain points INSERT queries are built dynamically,
but now i am facing a problem when the target table contains a SERIAL
field where NULL values are not allowed. Therefore I have two questions:

1) How can I find out if there is a serial field in a table, as
getColumnType() in ResultSetMetaData does not return a field indicating
SERIAL as far as I could see?
2) Why does it not work to issue a query like INSERT INTO
x(serial_field) VALUES(NULL) as the default of the "serial_field" is
nextval() anyway?

Thanks!


Christian Rengstl M.A.
Klinik und Poliklinik für Innere Medizin II
Kardiologie - Forschung
Universitätsklinikum Regensburg
B3 1.388
Franz-Josef-Strauss-Allee 11
93053 Regensburg
Tel.: +49-941-944-7230




Re: Serial data type

От
Kris Jurka
Дата:

On Fri, 30 Nov 2007, Christian Rengstl wrote:

> in my Java app at certain points INSERT queries are built dynamically,
> but now i am facing a problem when the target table contains a SERIAL
> field where NULL values are not allowed. Therefore I have two questions:
>
> 1) How can I find out if there is a serial field in a table, as
> getColumnType() in ResultSetMetaData does not return a field indicating
> SERIAL as far as I could see?

getColumnType returns a value from java.sql.Types, which doesn't have
SERIAL so there is no way to return it.
ResultSetMetaData.getColumnTypeName() should probably return serial, but
it doesn't at the moment.  ResultSetMetaData.isAutoIncrement() will work
as will DatabaseMetaData.getColumns().

> 2) Why does it not work to issue a query like INSERT INTO
> x(serial_field) VALUES(NULL) as the default of the "serial_field" is
> nextval() anyway?
>

When you've explicitly supplied a value (NULL in this case) the default is
not used.  Otherwise there would be no way to set a column to NULL that
had a default value.

Kris Jurka

Re: Serial data type

От
Christian Schröder
Дата:
Christian Rengstl wrote:
> 1) How can I find out if there is a serial field in a table, as
> getColumnType() in ResultSetMetaData does not return a field indicating
> SERIAL as far as I could see?
>
Creating a column with type serial is simply a shortcut for creating an
integer column and setting up a sequence which generates the default
value (see chapter 8.1.4 in den PostgreSQL docs):

chschroe=# create temp table temp(x serial);
NOTICE:  CREATE TABLE will create implicit sequence "temp_x_seq" for serial column "temp.x"
CREATE TABLE
chschroe=# \d temp
                       Table "pg_temp_7.temp"
 Column |  Type   |                    Modifiers
--------+---------+--------------------------------------------------
 x      | integer | not null default nextval('temp_x_seq'::regclass)


> 2) Why does it not work to issue a query like INSERT INTO
> x(serial_field) VALUES(NULL) as the default of the "serial_field" is
> nextval() anyway?
>
PostgreSQL behaves different from e.g. MySQL. When you set a column to
"null" in MySQL and this column has a default value this default is
instead inserted in the column. In PostgreSQL this leads to an error. (I
don't know which is compliant to the standard, but I assume PostgreSQL's
behaviour is correct.)
If you want a column to get its default value you have to omit it in the
insert statement. Of course, this only makes sense if your table has
more than this column. Consider the following example:

chschroe=# create temp table temp(x serial, foo text);
NOTICE:  CREATE TABLE will create implicit sequence "temp_x_seq" for serial column "temp.x"
CREATE TABLE
chschroe=# insert into temp(foo) values ('bar');
INSERT 0 1
chschroe=# select * from temp;
 x | foo
---+-----
 1 | bar
(1 row)

This works fine, whereas the following doesn't work at all:

chschroe=# insert into temp values (null, 'bar');
ERROR:  null value in column "x" violates not-null constraint

So it's not a jdbc problem, but a general misunderstanding in the way
PostgreSQL handles default values.

Regards,
    Christian

--
Deriva GmbH                         Tel.: +49 551 489500-42
Financial IT and Consulting         Fax:  +49 551 489500-91
Hans-Böckler-Straße 2                  http://www.deriva.de
D-37079 Göttingen

Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer


Re: Serial data type

От
Dave Cramer
Дата:
Christian,

You can use the keyword DEFAULT to get the default value in

  insert into sertest (id) values (DEFAULT);

You can also do

insert into sertest(id) values (nextval('sertest_id_seq'));

Dave
On 30-Nov-07, at 6:07 AM, Christian Schröder wrote:

> Christian Rengstl wrote:
>> 1) How can I find out if there is a serial field in a table, as
>> getColumnType() in ResultSetMetaData does not return a field
>> indicating
>> SERIAL as far as I could see?
>>
> Creating a column with type serial is simply a shortcut for creating
> an integer column and setting up a sequence which generates the
> default value (see chapter 8.1.4 in den PostgreSQL docs):
>
> chschroe=# create temp table temp(x serial);
> NOTICE:  CREATE TABLE will create implicit sequence "temp_x_seq" for
> serial column "temp.x"
> CREATE TABLE
> chschroe=# \d temp
>                      Table "pg_temp_7.temp"
> Column |  Type   |                    Modifiers
> --------+---------+--------------------------------------------------
> x      | integer | not null default nextval('temp_x_seq'::regclass)
>
>
>> 2) Why does it not work to issue a query like INSERT INTO
>> x(serial_field) VALUES(NULL) as the default of the "serial_field" is
>> nextval() anyway?
>>
> PostgreSQL behaves different from e.g. MySQL. When you set a column
> to "null" in MySQL and this column has a default value this default
> is instead inserted in the column. In PostgreSQL this leads to an
> error. (I don't know which is compliant to the standard, but I
> assume PostgreSQL's behaviour is correct.)
> If you want a column to get its default value you have to omit it in
> the insert statement. Of course, this only makes sense if your table
> has more than this column. Consider the following example:
>
> chschroe=# create temp table temp(x serial, foo text);
> NOTICE:  CREATE TABLE will create implicit sequence "temp_x_seq" for
> serial column "temp.x"
> CREATE TABLE
> chschroe=# insert into temp(foo) values ('bar');
> INSERT 0 1
> chschroe=# select * from temp;
> x | foo
> ---+-----
> 1 | bar
> (1 row)
>
> This works fine, whereas the following doesn't work at all:
>
> chschroe=# insert into temp values (null, 'bar');
> ERROR:  null value in column "x" violates not-null constraint
>
> So it's not a jdbc problem, but a general misunderstanding in the
> way PostgreSQL handles default values.
>
> Regards,
>   Christian
>
> --
> Deriva GmbH                         Tel.: +49 551 489500-42
> Financial IT and Consulting         Fax:  +49 551 489500-91
> Hans-Böckler-Straße 2                  http://www.deriva.de
> D-37079 Göttingen
>
> Deriva CA Certificate: http://www.deriva.de/deriva-ca.cer
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 4: Have you searched our list archives?
>
>              http://archives.postgresql.org


Re: Serial data type

От
"Albe Laurenz"
Дата:
Christian Rengstl wrote:
> in my Java app at certain points INSERT queries are built dynamically,
> but now i am facing a problem when the target table contains a SERIAL
> field where NULL values are not allowed. Therefore I have two questions:
> 
> 1) How can I find out if there is a serial field in a table, as
> getColumnType() in ResultSetMetaData does not return a field indicating
> SERIAL as far as I could see?

There's no really good implementation independent way, I think.

You can query the system catalogs with something like:

SELECT seq.relname
FROM pg_catalog.pg_depend dep    JOIN
     pg_catalog.pg_class tab     ON (dep.refobjid = tab.oid)     JOIN
     pg_catalog.pg_class seq     ON (dep.objid = seq.oid)        JOIN
     pg_catalog.pg_namespace sch ON (tab.relnamespace = sch.oid) JOIN
     pg_catalog.pg_attribute col ON (dep.refobjsubid = col.attnum)
WHERE sch.nspname = 'schema'  AND
      tab.relname = 'tabname' AND
      col.attname = 'colname' AND
      seq.relkind = 'S' AND dep.deptype = 'a';
This will return the name of the sequence for a serial column
and no row for another column.

Not nice, but maybe it is good enough for you.

> 2) Why does it not work to issue a query like INSERT INTO
> x(serial_field) VALUES(NULL) as the default of the "serial_field" is
> nextval() anyway?

Because the default value is only used if you do not insert
anything into the column. What you try is to explicitly insert
a NULL into the field.

If you want the default value, omit the column in the list of
fields.

Yours,
Laurenz Albe