Get data from nested tables - sql

I'm starting with object-oriented databases and I have a lot of questions about it :-(
Having the following structure:
CREATE OR REPLACE TYPE typeAuthor AS OBJECT(
aId INTEGER,
aName VARCHAR(60),
aSurname VARCHAR(200),
);
CREATE TABLE tableAuthors OF typeAuthor (aId PRIMARY KEY)
NESTED TABLE aArticles STORE AS aArticles_nt;
CREATE OR REPLACE TYPE typeListAuthors AS TABLE OF REF typeAuthor;
CREATE OR REPLACE TYPE typeUniversity AS OBJECT(
uniId INTEGER,
uAlias VARCHAR(16),
uName VARCHAR(20),
uLocation VARCHAR(150),
uAuthors typeListAuthors
);
CREATE TABLE tableUniversity OF typeUniversity (uniId PRIMARY KEY)
NESTED TABLE uAuthors STORE AS uAuthors_nt;
If I do a SELECT, for example:
SELECT u.uAuthors from tableUniversity u WHERE u.uniId = 1;
It returns all the data of the objects stored in the table that matches with the condition, but... How can I get only the names of the Authors?
I tried with
SELECT u.uAuthors.aName from tableUniversity u WHERE u.uniId = 1;
But it doesn't work.
Probably this is a basic question, but as I said, I'm starting with this and is being a little bit confusing to me.

You can unnest the inner collection with:
from tableUniversity u
cross join table (u.uAuthors) a
and dereference the value returned from that, which you can access as column_value:
SELECT deref(a.column_value)
from tableUniversity u
cross join table (u.uAuthors) a
and then you can access the aName field from each dereferenced object:
SELECT deref(a.column_value).aname
from tableUniversity u
cross join table (u.uAuthors) a
WHERE u.uniId = 1;
db<>fiddle

Related

How to create a projection from multi table

I have 2 tables as following:
CREATE TABLE public.test_employee
(
index int NOT NULL,
name varchar(100),
date_of_birth date,
address varchar(100),
id_dep int NOT NULL,
CONSTRAINT C_PRIMARY PRIMARY KEY (index) DISABLED
);
CREATE TABLE store.test_department
(
index int NOT NULL,
name varchar(100),
describe varchar(100),
CONSTRAINT C_PRIMARY PRIMARY KEY (index) DISABLED
);
I need to create a projection with many columns from the above two tables, My current code looks like this:
CREATE PROJECTION public.employee_department_super
(
idEmp,
idDep,
empName,
date_of_birth,
address,
depName,
describe
)
AS
SELECT e.index,
e.id_dep,
e.name,
e.date_of_birth,
e.address,
d.name,
d.describe
FROM
public.test_employee e
inner join store.test_department d
on e.id_dep=d.index
ORDER BY e.name
UNSEGMENTED ALL NODES;
But I received an error:
[Code: 9366, SQL State: 0A000] [Vertica][VJDBC](9366) ROLLBACK: Projections must select data from only one table
How can I solve this problem?
The answer is: you can't.
Join projections were a thing of a long gone past.
Vertica has begun to satisfy the need of reducing joins by the concept of the flattened table.
You add the two columns as flattened columns to your test_employee table, and they are automatically set whenever you insert new rows into the table.
ALTER TABLE public.test_employee
ADD depname VARCHAR(100)
DEFAULT(
SELECT name FROM store.test_department d WHERE d.index=id_dep
);
ALTER TABLE public.test_employee
ADD describe VARCHAR(100)
DEFAULT(
SELECT describe FROM store.test_department d WHERE d.index=id_dep
);
And the two flattened columns do not count against your license size.

How to make sure only one column is not null in postgresql table

I'm trying to setup a table and add some constraints to it. I was planning on using partial indexes to add constraints to create some composite keys, but ran into the problem of handling NULL values. We have a situation where we want to make sure that in a table only one of two columns is populated for a given row, and that the populated value is unique. I'm trying to figure out how to do this, but I'm having a tough time. Perhaps something like this:
CREATE INDEX foo_idx_a ON foo (colA) WHERE colB is NULL
CREATE INDEX foo_idx_b ON foo (colB) WHERE colA is NULL
Would this work? Additionally, is there a good way to expand this to a larger number of columns?
Another way to write this constraint is to use the num_nonulls() function:
create table table_name
(
a integer,
b integer,
check ( num_nonnulls(a,b) = 1)
);
This is especially useful if you have more columns:
create table table_name
(
a integer,
b integer,
c integer,
d integer,
check ( num_nonnulls(a,b,c,d) = 1)
);
You can use the following check:
create table table_name
(
a integer,
b integer,
check ((a is null) != (b is null))
);
If there are more columns, you can use the trick with casting boolean to integer:
create table table_name
(
a integer,
b integer,
...
n integer,
check ((a is not null)::integer + (b is not null)::integer + ... + (n is not null)::integer = 1)
);
In this example only one column can be not null (it simply counts not null columns), but you can make it any number.
One can do this with an insert/update trigger or checks, but having to do so indicates it could be done better. Constraints exist to give you certainty about your data so you don't have to be constantly checking if the data is valid. If one or the other is not null, you have to do the checks in your queries.
This is better solved with table inheritance and views.
Let's say you have (American) clients. Some are businesses and some are individuals. Everyone needs a Taxpayer Identification Number which can be one of several things such as a either a Social Security Number or Employer Identification Number.
create table generic_clients (
id bigserial primary key,
name text not null
);
create table individual_clients (
ssn numeric(9) not null
) inherits(generic_clients);
create table business_clients (
ein numeric(9) not null
) inherits(generic_clients);
SSN and EIN are both Taxpayer Identification Numbers and you can make a view which will treat both the same.
create view clients as
select id, name, ssn as tin from individual_clients
union
select id, name, ein as tin from business_clients;
Now you can query clients.tin or if you specifically want businesses you query business_clients.ein and for individuals individual_clients.ssn. And you can see how the inherited tables can be expanded to accommodate more divergent information between types of clients.

Searching a table using a user-defined function

I'm trying to write an SQL function that given a name of a game, it will allow me to search the table of games for that particular game and returns all the info about that game.
This is the code for the Games table:
CREATE TABLE Games(
game_id INT IDENTITY PRIMARY KEY,
name VARCHAR(50),
release_date VARCHAR(50),
rating VARCHAR(5),
min_age INT,
development_team_email VARCHAR(50) FOREIGN KEY REFERENCES Development_Teams,
release_conference INT FOREIGN KEY REFERENCES Conferences
)
And here is the what I could come up with when I was trying to write the function:
create function SearchGames(#game_name varchar(50))
returns table
begin
declare #game
Select (*)
From Games
where Games.name = #game_name
return #game
end
I'm getting a lot of syntax errors and I don't know what I'm doing wrong. Any help appreciated.
Use inline table valued function syntax and add schema:
create function dbo.SearchGames(#game_name varchar(50))
returns table
AS
RETURN (Select *
From Games
where Games.name = #game_name);
SqlFiddleDemo
If you use stored procedure you need to use:
CREATE TABLE ...;
INSERT INTO ... EXEC stored_procedure #args;
-- another operation on stored procedure resultset
while with inline table function you just:
SELECT * FROM dbo.SearchGames('aaa') GROUP BY ... HAVING ... ORDER BY;
I wouldn't recommend using a function for this, but rather a stored procedure:
Create Proc spSearchGames (#game_name Varchar (50))
As Begin
Select *
From Games
Where name = #game_name
End
Go
And executing it:
Exec spSearchGames 'YourGameName'

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');

How to combine particular rows in a pl/pgsql function that returns set of a view row type?

I have a view, and I have a function that returns records from this view.
Here is the view definition:
CREATE VIEW ctags(id, name, descr, freq) AS
SELECT tags.conc_id, expressions.name, concepts.descr, tags.freq
FROM tags, concepts, expressions
WHERE concepts.id = tags.conc_id
AND expressions.id = concepts.expr_id;
The column id references to the table tags, that, references to another table concepts, which, in turn, references to the table expressions.
Here are the table definitions:
CREATE TABLE expressions(
id serial PRIMARY KEY,
name text,
is_dropped bool DEFAULT FALSE,
rank float(53) DEFAULT 0,
state text DEFAULT 'never edited',
UNIQUE(name)
);
CREATE TABLE concepts(
id serial PRIMARY KEY,
expr_id int NOT NULL,
descr text NOT NULL,
source_id int,
equiv_p_id int,
equiv_r_id int,
equiv_len int,
weight int,
is_dropped bool DEFAULT FALSE,
FOREIGN KEY(expr_id) REFERENCES expressions,
FOREIGN KEY(source_id),
FOREIGN KEY(equiv_p_id) REFERENCES concepts,
FOREIGN KEY(equiv_r_id) REFERENCES concepts,
UNIQUE(id,equiv_p_id),
UNIQUE(id,equiv_r_id)
);
CREATE TABLE tags(
conc_id int NOT NULL,
freq int NOT NULL default 0,
UNIQUE(conc_id, freq)
);
The table expressions is also referenced from my view (ctags).
I want my function to combine rows of my view, that have equal values in the column name and that refer to rows of the table concepts with equal values of the column equiv_r_id so that these rows are combined only once, the combined row has one (doesn't matter which) of the ids, the value of the column descr is concatenated from the values of the rows being combined, and the row freq contains the sum of the values from the rows being combined. I have no idea how to do it, any help would be appreciated.
Basically, what you describe looks like this:
CREATE FUNCTION f_test()
RETURNS TABLE(min_id int, name text, all_descr text, sum_freq int) AS
$x$
SELECT min(t.conc_id) -- AS min_id
,e.name
,string_agg(c.descr, ', ') -- AS all_descr
,sum(t.freq) -- AS sum_freq
FROM tags t
JOIN concepts c USING (id)
JOIN expressions e ON e.id = c.expr_id;
-- WHERE e.name IS DISTINCT FROM
$x$
LANGUAGE sql;
Major points:
I ignored the view ctags altogether as it is not needed.
You could also write this as View so far, the function wrapper is not necessary.
You need PostgreSQL 9.0+ for string_agg(). Else you have to substitute with
array_to_string(array_agg(c.descr), ', ')
The only unclear part is this:
and that refer to rows of the table concepts with equal values of the column equiv_r_id so that these rows are combined only once
Waht column exactly refers to what column in table concepts?
concepts.equiv_r_id equals what exactly?
If you can clarify that part, I might be able to incorporate it into the solution.