creating schema with a table containing serial field - sql

How do I create (in a single SQL command) a schema and a table in it, but with the table containing a serial column (in Postgres) ?
For example, here I am attempting to create schema zoo with table animals from type animal_t with serial column animal_id:
DROP TYPE IF EXISTS animal_t CASCADE;
CREATE TYPE animal_t AS (
animal_id integer,
animal_name varchar
);
CREATE SCHEMA zoo
CREATE TABLE animals OF animal_t
animal_id WITH OPTIONS NOT NULL DEFAULT nextval('animals_animal_id_seq')
CREATE SEQUENCE animals_animal_id_seq OWNED by animals.animal_id
;
Notes:
CREATE SCHEMA only accepts CREATE TABLE or CREATE SEQUENCE, it does not accept ALTER , this is why I have to do all of this in a single SQL sentence.
Result:
-bash-4.3$ psql dev < animal.sql
DROP TYPE
CREATE TYPE
ERROR: syntax error at or near "animal_id"
LINE 3: animal_id WITH OPTIONS NOT NULL DEFAULT nextval('animals_a...
^
-bash-4.3$

You have two options
simplify your statement and get rid of the object type
CREATE SCHEMA zoo
CREATE table animal
(
animal_id serial,
animal_name varchar
);
use a search path if you want to avoid to prefix the table with a schema name:
DROP TYPE IF EXISTS animal_t CASCADE;
CREATE TYPE animal_t AS (
animal_id integer,
animal_name varchar
);
CREATE SCHEMA zoo;
set search_path = zoo;
CREATE SEQUENCE animals_animal_id_seq;
CREATE TABLE animals OF animal_t
animal_id WITH OPTIONS NOT NULL DEFAULT nextval('animals_animal_id_seq');
alter sequence animals_animal_id_seq owned by animals.animal_id;
After creating the type and the schema, the current schema is set to the just created one, so all subsequent statements use zoo as the default schema.
Note that you can do this in a single transaction if that is another reason for you to use the "extended" create schema syntax.

I think the following should do it. The idea is to ALTER schema_name.thing:
CREATE SCHEMA zoo
CREATE TABLE animals OF animal_t ( animal_id WITH OPTIONS NOT NULL )
;
CREATE SEQUENCE zoo.animals_animal_id_seq OWNED BY zoo.animals.animal_id;
ALTER TABLE zoo.animals ALTER animal_id SET DEFAULT nextval('zoo.animals_animal_id_seq');

Related

Why is the column not altering when I try to convert it to UUID?

I have a primary key column in my SQL table in PostgreSQL named "id". It is a "bigseries" column. I want to convert the column to a "UUID" column. It entered the below command in the terminal:
alter table people alter column id uuid;
and
alter table people alter column id uuid using (uuid_generate_v4());
but neither of them worked.
In both tries I got the error message
ERROR: syntax error at or near "uuid"
LINE 1: alter table people alter column id uuid using (uuid_generate...
What is the correct syntax?
First of all uuid_generate_v4() is a function which is provided by an extension called uuid-ossp. You should have install that extension by using;
CREATE EXTENSION uuid-ossp;
Postgresql 13 introduced a new function which does basically the same without installing extension. The function is called gen_random_uuid()
Suppose that we have a table like the one below;
CREATE TABLE people (
id bigserial primary key,
data text
);
The bigserial is not a real type. It's a macro which basically creates bigint column with default value and a sequence. The default value is next value of that sequence.
For your use case, to change data type, you first should drop the old default value. Then, alter the type and finally add new default value expression. Here is the sample:
ALTER TABLE people
ALTER id DROP DEFAULT,
ALTER id TYPE uuid using (gen_random_uuid() /* or uuid_generate_v4() */ ),
ALTER id SET DEFAULT gen_random_uuid() /* or uuid_generate_v4() */ ;
CREATE TABLE IF NOT EXISTS people (
id uuid NOT NULL CONSTRAINT people_pkey PRIMARY KEY,
address varchar,
city varchar(255),
country varchar(255),
email varchar(255),
phone varchar(255)
);
This is the correct syntax to create table in postgres SQL, it's better to do these constraints at beginning to avoid any error.
For using alter command you would do the following:
ALTER TABLE customer ADD COLUMN cid uuid PRIMARY KEY;
Most of errors that you could find while writing command either lower case or undefined correct the table name or column.

Can I change an attribute name from a table derived from a type?

Folowing the Object-Relational Database model, I wanted to create the tables or_doctor and or_recepcionist derived from the type t_employee.
Here, follows the type structure:
DROP TYPE t_employee FORCE;
CREATE OR REPLACE TYPE t_employee AS OBJECT (
num_employee INTEGER,
name_employee VARCHAR2(50),
birthdate_employee DATE
);
And here, the tables' structure:
DROP TABLE or_doctor CASCADE CONSTRAINTS;
CREATE TABLE or_doctor OF t_employee (
PRIMARY KEY (num_employee),
name_employee NOT NULL,
birthdate_employee NOT NULL
) OBJECT IDENTIFIER IS SYSTEM GENERATED;
DROP TABLE or_recepcionist CASCADE CONSTRAINTS;
CREATE TABLE or_recepcionist OF t_employee (
PRIMARY KEY (num_employee),
name_employee NOT NULL,
birthdate_employee NOT NULL
) OBJECT IDENTIFIER IS SYSTEM GENERATED;
Doing so, the attributes names, on both tables, will end up with "employee". Could I change the attribute name so they are specific in each table at the moment I'm creating the table?
E.G.:
Table or_doctor: num_doct, name_doct, birthdate_doct.
Table or_recepcionist: num_recep, name_recep, birthdate_recep.
As a frame challenge, don't add a suffix to your identifiers then you don't need to worry about the suffix being incorrect:
CREATE TYPE t_employee AS OBJECT (
num INTEGER,
name VARCHAR2(50),
birthdate DATE
);
CREATE TABLE or_doctor OF t_employee (
PRIMARY KEY (num),
name NOT NULL,
birthdate NOT NULL
) OBJECT IDENTIFIER IS SYSTEM GENERATED;
CREATE TABLE or_receptionist OF t_employee (
PRIMARY KEY (num),
name NOT NULL,
birthdate NOT NULL
) OBJECT IDENTIFIER IS SYSTEM GENERATED;
If you try to rename the column:
ALTER TABLE or_doctor RENAME COLUMN name TO name_doctor;
Then you will get the error:
ORA-23291: Only base table columns may be renamed
If you are using object-derived tables then you appear to be stuck with the identifiers from the object; so, make the object names generic so that they are appropriate in every place they are going to be used.

ERROR: relation "schema.TableName_Id_seq" does not exist - when creating table in a new database

I'm having an issue where I used pgAdmin4's GUI to create a SQL table, and I want to use to generated CREATE TABLE script to create this same table in another database.
When I run the CREATE TABLE script generated by pgAdmin4 in my new database, I get the following error:
ERROR: relation "schema.TableName_Id_seq" does not exist
So, it appears that the issue is with my auto-incrementing id column that I created as type SERIAL.
The CREATE TABLE script as provided by pgAdmin4:
-- Table: myschema.TableName
-- DROP TABLE myschema."TableName";
CREATE TABLE myschema."TableName"
(
"Id" integer NOT NULL DEFAULT nextval('myschema."TableName_Id_seq"'::regclass),
/* Other columns here */
CONSTRAINT "TableName_pkey" PRIMARY KEY ("Id")
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE myschema."TableName"
OWNER to JoshuaSchlichting;
Why can't the CREATE TABLE script be used in another database? The relation "schema.TableName_Id_seq" didn't exist in the original database prior to be creating that table. What's happening that is different?
The DDL script provided by pgAdmin4 is not complete. When the table was created, there was an implicit creation of a sequence because of the SERIAL type being select for the Id column.
You can find this newly create sequence with pgAdmin4. To do this, go to
-> your server
-> your database
-> your schema
-> Sequences
-> Right click TableName_Id_seq
-> choose "Create script"
This reveals the script used to create this sequence. In this instance, the following was revealed:
-- SEQUENCE: myschema.TableName
-- DROP SEQUENCE myschema."TableName";
CREATE SEQUENCE myschema."TableName"
INCREMENT 1
START 1
MINVALUE 1
MAXVALUE 2147483647
CACHE 1;
The use of the CREATE SEQUENCE script can be avoided by changing the line of code used to create the Id column in the CREATE TABLE script. Example below:
original line:
"Id" integer NOT NULL DEFAULT nextval('myschema."TableName_Id_seq"'::regclass),
changed to: "Id" SERIAL NOT NULL,

Adding a NOT NULL column to a Redshift table

I'd like to add a NOT NULL column to a Redshift table that has records, an IDENTITY field, and that other tables have foreign keys to.
In PostgreSQL, you can add the column as NULL, fill it in, then ALTER it to be NOT NULL.
In Redshift, the best I've found so far is:
ALTER TABLE my_table ADD COLUMN new_column INTEGER;
-- Fill that column
CREATE TABLE my_table2 (
id INTEGER IDENTITY NOT NULL SORTKEY,
(... all the fields ... )
new_column INTEGER NOT NULL,
PRIMARY KEY(id)
) DISTSTYLE all;
UNLOAD ('select * from my_table')
to 's3://blah' credentials '<aws-auth-args>' ;
COPY my_table2
from 's3://blah' credentials '<aws-auth-args>'
EXPLICIT_IDS;
DROP table my_table;
ALTER TABLE my_table2 RENAME TO my_table;
-- For each table that had a foreign key to my_table:
ALTER TABLE another_table ADD FOREIGN KEY(my_table_id) REFERENCES my_table(id)
Is this the best way of achieving this?
You can achieve this w/o having to load to S3.
modify the existing table to create the desired column w/ a default value
update that column in some way (in my case it was copying from another column)
create a new table with the column w/o a default value
insert into the new table (you must list out the columns rather than using (*) since the order may be the same (say if you want the new column in position 2)
drop the old table
rename the table
alter table to give correct owner (if appropriate)
ex:
-- first add the column w/ a default value
alter table my_table_xyz
add visit_id bigint NOT NULL default 0; -- not null but default value
-- now populate the new column with whatever is appropriate (the key in my case)
update my_table_xyz
set visit_id = key;
-- now create the new table with the proper constraints
create table my_table_xzy_new
(
key bigint not null,
visit_id bigint NOT NULL, -- here it is not null and no default value
adt_id bigint not null
);
-- select all from old into new
insert into my_table_xyz_new
select key, visit_id, adt_id
from my_table_xyz;
-- remove the orig table
DROP table my_table_xzy_events;
-- rename the newly created table to the desired table
alter table my_table_xyz_new rename to my_table_xyz;
-- adjust any views, foreign keys or permissions as required

sqlite3 explain table_name

In mysql you can view a table's structure via explain tablename; What is the equivalent for sqlite3?
I believe ".schema tablename" is what you're looking for.
You can use .schema in the Command Line Shell:
With no arguments, the ".schema"
command shows the original CREATE
TABLE and CREATE INDEX statements that
were used to build the current
database. If you give the name of a
table to ".schema", it shows the
original CREATE statement used to make
that table and all if its indices.
This was already answered in a more generic way here.
Edit:
Note that .schema will also give you INDEXES that match the same name.
Example:
CREATE TABLE job (
id INTEGER PRIMARY KEY,
data VARCHAR
);
CREATE TABLE job_name (
id INTEGER PRIMARY KEY,
name VARCHAR
);
CREATE INDEX job_idx on job(data);
Note the differences between:
sqlite> SELECT sql FROM SQLITE_MASTER WHERE type = 'table' AND name = 'job';
CREATE TABLE job (
id INTEGER PRIMARY KEY,
data VARCHAR
)
sqlite> SELECT sql FROM SQLITE_MASTER WHERE name = 'job_idx';
CREATE INDEX job_idx on job(data)
and
sqlite> .schema job
CREATE TABLE job (
id INTEGER PRIMARY KEY,
data VARCHAR
);
CREATE INDEX job_idx on job(data);
Including the semi-colon at the end of the queries.