SCOPE for a table of REFs - sql

I am designing an object-relational model with Oracle (18.4.0) and I would like to add a SCOPE constraint to a table type column of an object table. Is it possible? Here a simplified model:
CREATE OR REPLACE TYPE t_cycler AS OBJECT (
name VARCHAR2(50)
);
CREATE TABLE cycler OF t_cycler (
name PRIMARY KEY
);
CREATE OR REPLACE TYPE t_cycler_list IS TABLE OF REF t_cycler;
CREATE OR REPLACE TYPE t_team AS OBJECT (
name VARCHAR2(50),
cyclers t_cycler_list
);
CREATE TABLE team OF t_team (
name PRIMARY KEY
)
NESTED TABLE cyclers STORE AS cyclers_tab;
I need that team.cyclers only contains REFs to objects in cycler. I look into the documentation but unfortunately it does not say a lot about SCOPE constraint, like here:
You can constrain a column type, collection element, or object type
attribute to reference a specified object table. Use the SQL
constraint subclause SCOPE IS when you declare the REF.
But the only example it provides is about a simple column type. I tried specifying SCOPE IS cycler in several ways inside the creation of the team table but with no results.

You want to add the scope to the COLUMN_VALUE pseudo-column of the nested table:
ALTER TABLE cyclers_tab ADD SCOPE FOR ( COLUMN_VALUE ) IS cycler;
If you then do:
INSERT INTO cycler ( name ) VALUES ( 'c1.1' );
INSERT INTO cycler ( name ) VALUES ( 'c1.2' );
INSERT INTO team (
name,
cyclers
) VALUES (
'team1',
t_cycler_list(
( SELECT REF(c) FROM cycler c WHERE name = 'c1.1' ),
( SELECT REF(c) FROM cycler c WHERE name = 'c1.2' )
)
);
Then you can insert the row. But, if you have another table of the same object type:
CREATE TABLE cycler2 OF t_cycler (
name PRIMARY KEY
);
INSERT INTO cycler2 ( name ) VALUES ( 'c2.1' );
And try to do:
INSERT INTO team (
name,
cyclers
) VALUES (
'team2',
t_cycler_list(
( SELECT REF(c) FROM cycler2 c WHERE name = 'c2.1' )
)
);
Then you get the error:
ORA-22889: REF value does not point to scoped table
db<>fiddle here

Related

Comparing UUIDs in postgres

Let's say I create two tables in Postgres with UUID as the PRIMARY KEY. These UUID are generated using the uuid-ossp module in Postgres: https://www.postgresql.org/docs/9.5/static/uuid-ossp.html
CREATE TABLE f(
idFoo UUID PRIMARY KEY DEFAULT gen_random_uuid(),
foo TEXT
);
CREATE TABLE b (
idBar UUID,
bar text,
FOREIGN KEY (idBar) REFERENCES foo(idFoo)
);
I then want to create a VIEW based on the above two tables:
CREATE OR REPLACE VIEW foobar AS (
SELECT fooid, barid
FROM foo, bar
WHERE f.idFoo = b.idBar
-- AND some other condition --
);
Question: How do I compare the UUID types?
Don't compare UUID, you're looking to JOIN on them:
CREATE OR REPLACE VIEW foobar AS (
SELECT f.foo, b.bar, f.id
FROM f JOIN b USING (id)
WHERE -- some other condition --
);
To JOIN on different columns, you can:
CREATE OR REPLACE VIEW foobar AS (
SELECT f.foo, b.bar, idFoo, idBar
FROM f JOIN b ON (idFoo = idBar)
WHERE -- some other condition --
);
(Of course, because idFoo = idBar, there's no need to include both in your second select).

Oracle SQL Objects - Unique/Foreign Key on references

Is it possible to set unique/foreign keys on reference fields when using SQL Objects? For example, assuming I have the following table:
create table MY_TABLE (
SOME_REFERENCE ref MY_TYPE
);
Can I set a unique key on a reference? Something like this:
alter table MY_TABLE modify (constraint ABC unique(SOME_REFERENCE))
(Which gives ORA-02329: column of datatype REF cannot be unique or a primary key)
Is it possible to achive something like unique/foreign keys on reference fields (Maybe by using workarounds?)
There is the workaround but it's tricky.
create type my_type as object
( id number, v varchar2(20));
create table my_type_table of my_type;
insert into my_type_table values(1,'a');
create table MY_TABLE (
SOME_REFERENCE ref MY_TYPE
);
create or replace function test_func(p_ref ref MY_TYPE) return number DETERMINISTIC
is
v_typ MY_TYPE;
begin
SELECT DEREF(p_ref) INTO v_typ FROM DUAL;
return v_typ.id;
end;
CREATE UNIQUE INDEX fn_idx_un ON MY_TABLE (test_func(SOME_REFERENCE));
And test.
insert into my_type_table values(1,'a');
insert into MY_TABLE SELECT REF(e) FROM my_type_table e; (*1)
insert into MY_TABLE SELECT REF(e) FROM my_type_table e; (*2)
*1 - works fine, and row is inserted.
*2 - execption is raised. ORA-00001: unique constraint (FN_IDX_UN) violated

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

Inserting a ref value into an object table

I have an assignment for college and I'm having trouble doing one of my inserts.
I have created an object called memeber
CREATE TYPE memeber AS OBJECT
(
member_id INTEGER,
member_name VARCHAR(30),
member_jobtitle VARCHAR(30),
member_skills skills_list,
past_projects past_projects_NTT
)
Then I created this object table
CREATE TABLE project_resources of MEMEBER
(
MEMBER_ID PRIMARY KEY,
MEMBER_NAME NOT NULL
)NESTED TABLE past_projects STORE AS PROJ_EXT;
Then I had to create an object called project as follows
CREATE TYPE project as OBJECT
(
PROJECT_ID INTEGER,
PROJECT_ASSIGNED_MEMBER REF MEMEBER,
PROJECT_TITLE VARCHAR2(30)
);
I had to create an object table of type project and alter it
CREATE TABLE PROJECT_TABLE OF PROJECT;
ALTER TABLE PROJECT_TABLE ADD PRIMARY KEY(PROJECT_ID);
ALTER TABLE PROJECT_TABLE ADD (CONSTRAINT NULL_CHK CHECK(PROJECT_TITLE IS NOT NULL);
No this is where I start to have trouble, I have been shown how to insert values to a table when all the values are of type ref, but when I include the other types I'm unsure of the syntax.
This was my attempt:
INSERT INTO PROJECT_TABLE
SELECT 1, REF(M)
FROM MEMEBER M
WHERE M.MEMBER_ID =1, 'KING KONG';
Could someone shed some light on the syntax for me please?
After some more research I found the solution:
INSERT INTO PROJECT_TABLE
(PROJECT_ID,
PROJECT_ASSIGNED_MEMBER,
PROJECT_TITLE)VALUES(
2,
(SELECT REF(M) FROM project_resources M WHERE M.member_id = 2),
'Bomb');

Create a table of two types in PostgreSQL

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.