Create a table of two types in PostgreSQL - sql

I have created two types:
Create Type info_typ_1 AS (
Prod_id integer,
category integer);
Create Type movie_typ AS(
title varchar(50),
actor varchar(50),
price float);
And I want to create a table that consists of these two types. I know that for a table that consists of one type, it's:
CREATE TABLE Table1 of type1
(
primary key(prod_id)
);
Is there any way to do that for the two types I created above?
What I tried doing(which is wrong), is creating a third type that contains the first two:
Create Type info_ AS (
info info_typ_1,
movie movie_typ);
and then creating the table:
CREATE TABLE table1 of info_
(
primary key(Prod_id)
);
But it doesn't work. I get this error:
ERROR: column "prod_id" named in key does not exist
LINE 3: primary key(Prod_id)
^
********** Error **********
ERROR: column "prod_id" named in key does not exist
SQL state: 42703
Character: 43

You cannot make prod_id the primary key of table1 because the only columns are the two composite types info and movie. You cannot access the base types of these composite types in a PRIMARY KEY clause.
What you were trying to do works with a pk constraint on info or movie.
Except, it's probably not what you were looking for, which is not possible this way.
You could implement something like this with ...
Inheritance
Here you can inherit from multiple parent tables (substitute for your types). Example:
CREATE TABLE info (
prod_id integer
,category integer
);
CREATE TABLE movie (
title text
,actor text
,price float
);
CREATE TABLE movie_info (
PRIMARY KEY(prod_id) -- now we can use the base column!
)
INHERITS (info, movie);
INSERT INTO movie_info (prod_id, category, title, actor, price)
VALUES (1, 2, 'who donnit?', 'James Dean', '15.90');
SELECT * FROM movie_info;
-> SQLfiddle demonstrating both.
Be sure to read about limitations of inheritance in the manual.

Related

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.

Oracle - How to get a number from an object in a sql query?

I have this object:
CREATE TYPE CarType AS OBJECT(
price_id NUMBER,
quantity NUMBER.
MAP MEMBER FUNCTION get_price_id RETURN NUMBER
);
and this table:
CREATE TABLE Cars(
carid NUMBER PRIMARY KEY,
carinfo cartype,
CONSTRAINT car_fk FOREIGN KEY(carinfo.price_id) REFERENCES prices(price_id)
);
and I want to get the carid,price_id from Cars table with a sql query.
You must remember about aliasing your table and accessing columns with object type using alias, otherwise you will get ORA-00904 invalid identifier error.
This query will work:
SELECT C.CARID, C.CARINFO.PRICE_ID, C.CARINFO.QUANTITY FROM CARS C;
But this will not:
SELECT CARS.CARID, CARS.CARINFO.PRICE_ID, CARS.CARINFO.QUANTITY FROM CARS;

Moving table columns to new table and referencing as foreign key in PostgreSQL

Suppose we have a DB table with fields
"id", "category", "subcategory", "brand", "name", "description", etc.
What's a good way of creating separate tables for
category, subcategory and brand
and the corresponding columns and rows in the original table becoming foreign key references?
To outline the operations involved:
get all unique values in each column of the original table which should become foreign keys;
create tables for those
create foreign key reference columns in the original table (or a copy)
In this case, the PostgreSQL DB is accessed via Sequel in a Ruby app, so available interfaces are the command line, Sequel, PGAdmin, etc...
The question: how would you do this?
-- Some test data
CREATE TABLE animals
( id SERIAL NOT NULL PRIMARY KEY
, name varchar
, category varchar
, subcategory varchar
);
INSERT INTO animals(name, category, subcategory) VALUES
( 'Chimpanzee' , 'mammals', 'apes' )
,( 'Urang Utang' , 'mammals', 'apes' )
,( 'Homo Sapiens' , 'mammals', 'apes' )
,( 'Mouse' , 'mammals', 'rodents' )
,( 'Rat' , 'mammals', 'rodents' )
;
-- [empty] table to contain the "squeezed out" domain
CREATE TABLE categories
( id SERIAL NOT NULL PRIMARY KEY
, category varchar
, subcategory varchar
, UNIQUE (category,subcategory)
);
-- The original table needs a "link" to the new table
ALTER TABLE animals
ADD column category_id INTEGER -- NOT NULL
REFERENCES categories(id)
;
-- FK constraints are helped a lot by a supportive index.
CREATE INDEX animals_categories_fk ON animals (category_id);
-- Chained query to:
-- * populate the domain table
-- * initialize the FK column in the original table
WITH ins AS (
INSERT INTO categories(category, subcategory)
SELECT DISTINCT a.category, a.subcategory
FROM animals a
RETURNING *
)
UPDATE animals ani
SET category_id = ins.id
FROM ins
WHERE ins.category = ani.category
AND ins.subcategory = ani.subcategory
;
-- Now that we have the FK pointing to the new table,
-- we can drop the redundant columns.
ALTER TABLE animals DROP COLUMN category, DROP COLUMN subcategory;
-- show it to the world
SELECT a.*
, c.category, c.subcategory
FROM animals a
JOIN categories c ON c.id = a.category_id
;
Note: the fragment:
WHERE ins.category = ani.category
AND ins.subcategory = ani.subcategory
will lead to problems if these columns contain NULLs.
It would be better to compare them using
(ins.category,ins.subcategory)
IS NOT DISTINCT FROM
(ani.category,ani.subcategory)
I'm not sure I completely understand your question, if this doesn't seem to answer it, then please leave a comment and possibly improve your question to clarify, but it sounds like you want to do a CREATE TABLE xxx AS. For example:
CREATE TABLE category AS (SELECT DISTINCT(category) AS id FROM parent_table);
Then alter the parent_table to add a foreign key constraint.
ALTER TABLE parent_table ADD CONSTRAINT category_fk FOREIGN KEY (category) REFERENCES category (id);
Repeat this for each table you want to create.
Here is the related documentation:
CREATE TABLE
ALTER TABLE
Note: code and references are for Postgresql 9.4

How to CREATE TABLE with disjoint relationship in SQL

I am trying to create a table using a disjoint subtype relationship.
For example, if the Supertype is furniture, and I have 3 Subtypes of furniture: chair, couch, and table.
Then:
CREATE TABLE Furniture
(order_num NUMBER(15), desc VARCHAR2(20), type VARCHAR2(10));
How do I make an option to pick type of chair, couch or table?
You can use REFERENCES in the CREATE TABLE.
CREATE TABLE Furniture_SubTypes
(
sub_type VARCHAR(10) PRIMARY KEY
);
INSERT INTO Furniture_SubTypes VALUES ('Chair');
INSERT INTO Furniture_SubTypes VALUES ('Couch');
INSERT INTO Furniture_SubTypes VALUES ('Table');
CREATE TABLE Furniture
(
order_num NUMBER,
description VARCHAR(20),
sub_type REFERENCES Furniture_SubTypes(sub_type)
);
Use a check constraint:
CREATE TABLE Furniture (
order_num NUMBER(15),
description VARCHAR2(20),
type VARCHAR2(10),
check (type in ('chair', 'couch', 'table'))
);
Note that desc is a poor choice for a column name, because it is a keyword in SQL (used for order by).

Creating SQL table with array value

What is the best way to create table in SQL database for my situation? Option 1 or Option 2?
TMyRecord = record
id : integer;
name : string;
price : Array [0.100] of double;
If i want to create table in SQL database,
Option 1: - Creating one table and use ID and Name for all price entries.
CREATE TABLE My_Record
(
ID int,
Name varchar(255),
price float,
);
or Option 2: - use two tables and link each other?
CREATE TABLE My_Record
(
ID int,
Name varchar(255),
price float,
PRIMARY KEY (P_Id)
);
CREATE TABLE My_Record_ArrayData
(
FOREIGN KEY (ID) REFERENCES My_Record(ID)
price float,
);
Thanks in advance.
Option 2 is better, as you don't repeat Name column for each price value.
Also you just need to store ID,Name in My_Record in the second option , all price values can go to My_Record_ArrayData
another option is to go with XML data type to store all price values then you will have only one table with all values for that Name.