Postgres reverse inheritance? (inherit rows from parent table) - postgresql

I have a number of records that are common to all schemas. I place these records in a shared schema table, and would like to inheritthe rows of record from this shared parent table in each of the child schemas.
Suppose I have the following schemas:
CREATE SCHEMA parent;
CREATE SCHEMA a;
CREATE SCHEMA b;
CREATE TABLE parent.component (product_id serial PRIMARY KEY, title text);
CREATE TABLE a.component () INHERITS (parent.component);
CREATE TABLE b.product () INHERITS (parent.component);
INSERT INTO parent.component(title) VALUES ('parent');
INSERT INTO a.component(title) VALUES ('a_test') ,('a_test2') ;
INSERT INTO b.component(title) VALUES ('b_test') ,('b_test2');
Is there a way to select the union of rows from the parent and either a.component or b.component when I issue a select on either a or b ?
So for example:
SELECT * FROM a.component;
returns rows:
id | title
---------------
1 parent
2 a_test
3 a_test2

PostgreSQL has multiple inheritance, so a table can be the child of many tables. You could try to inherit in the other direction!
But maybe a simple UNION ALL query is a simpler and better solution.

Related

How deep can we go in levels of nested tables in oracle 12c?

i am trying to do the folowing:
1) create or replace type transaction as object (date Date, description
varchar(30));
create or replace type T_transaction as table of transaction;
2) create or replace type account as object (id int, description varchar(30),
t_transaction T_transaction)
nested table t_transaction store as xxx1;
create or replace type T_account as table of account;
3) create or replace type user as object (id int, descr varchar(30), t_account
T_account)
nested table t_account store as xxx2;
create or replace type T_user as table of user;
4) create or replace table banks (name varchar(20), users T_user)
nested table users store as xxx3;
first 2 types were created successfully, but "create or replace type account..." is giving -> Warning: Type created with compilation errors.
is there an advice for creating such database using multiple level of nested tables ?
Edit:
I did some research on the subject (object nesting limitations) and here are my findings:
According to Database Limits,
every column of a nested table is in effect added to the columns of the host table and the maximum total number of columns in a table is 1000.
So this would be the official upper limit (in case every nested table had a single column).
However, when I did actual testing (on 11g and 12c), I weren't able to create a table with a nesting depth more than 50 because of error
ORA-00036: maximum number of recursive SQL levels (50) exceeded.
Thus I conclude that the maximum possible depth of nesting is 50.
Initial answer:
I am not aware of limits on objects nesting but I think they should be reasonably permissive.
Your code fails because you made a few mistakes:
1. Using type names as column names (date, t_account, etc.);
2. Using nested table clause in a wrong place;
The code should go like this:
create or replace type transaction_type as object (tx_date Date, description varchar2(30));
create or replace type transaction_tab as table of transaction_type;
create or replace type account_type as object (id int, description varchar(30),
transactions transaction_tab);
create or replace type account_tab as table of account_type;
create or replace type user_type as object (id int, descr varchar(30), accounts account_tab);
create or replace type user_tab as table of user_type;
CREATE table banks (name varchar(20), users user_tab)
nested table users store as xxx3 (
nested table accounts store as xxx2 (
nested table transactions store as xxx1
));
Checking
INSERT INTO banks VALUES (
'John', user_tab(
user_type(1
,'regular user'
, account_tab(
account_type(1
,'regular account'
, transaction_tab(transaction_type(
trunc(sysdate)
, 'regular transaction'))
))
)));
SQL> SELECT *FROM banks;
NAME
--------------------
USERS(ID, DESCR, ACCOUNTS(ID, DESCRIPTION, TRANSACTIONS(TX_DATE, DESCRIPTION)))
--------------------------------------------------------------------------------
John
USER_TAB(USER_TYPE(1, 'regular user', ACCOUNT_TAB(ACCOUNT_TYPE(1, 'regular accou
nt', TRANSACTION_TAB(TRANSACTION_TYPE('04-APR-18', 'regular transaction'))))))
Selecting nested table columns
SELECT b.name, u.id, u.descr, a.id, a.description
FROM banks b, table(b.users) u, table(u.accounts) a
WHERE u.descr = 'regular user' AND a.description = 'regular account'
NAME ID DESCR ID DESCRIPTION
----- --- ------------- --- ----------------
John 1 regular user 1 regular account

Can the categories in the postgres tablefunc crosstab() function be integers?

It's all in the title. Documentation has something like this:
SELECT *
FROM crosstab('...') AS ct(row_name text, category_1 text, category_2 text);
I have two tables, lab_tests and lab_tests_results. All of the lab_tests_results rows are tied to the primary key id integer in the lab_tests table. I'm trying to make a pivot table where the lab tests (identified by an integer) are row headers and the respective results are in the table. I can't get around a syntax error at or around the integer.
Is this possible with the current set up? Am I missing something in the documentation? Or do I need to perform an inner join of sorts to make the categories strings? Or modify the lab_tests_results table to use a text identifier for the lab tests?
Thanks for the help, all. Much appreciated.
Edit: Got it figured out with the help of Dmitry. He had the data layout figured out, but I was unclear on what kind of output I needed. I was trying to get the pivot table to be based on batch_id numbers in the lab_tests_results table. Had to hammer out the base query and casting data types.
SELECT *
FROM crosstab('SELECT lab_tests_results.batch_id, lab_tests.test_name, lab_tests_results.test_result::FLOAT
FROM lab_tests_results, lab_tests
WHERE lab_tests.id=lab_tests_results.lab_test AND (lab_tests.test_name LIKE ''Test Name 1'' OR lab_tests.test_name LIKE ''Test Name 2'')
ORDER BY 1,2'
) AS final_result(batch_id VARCHAR, test_name_1 FLOAT, test_name_2 FLOAT);
This provides a pivot table from the lab_tests_results table like below:
batch_id |test_name_1 |test_name_2
---------------------------------------
batch1 | result1 | <null>
batch2 | result2 | result3
If I understand correctly your tables look something like this:
CREATE TABLE lab_tests (
id INTEGER PRIMARY KEY,
name VARCHAR(500)
);
CREATE TABLE lab_tests_results (
id INTEGER PRIMARY KEY,
lab_tests_id INTEGER REFERENCES lab_tests (id),
result TEXT
);
And your data looks something like this:
INSERT INTO lab_tests (id, name)
VALUES (1, 'test1'),
(2, 'test2');
INSERT INTO lab_tests_results (id, lab_tests_id, result)
VALUES (1,1,'result1'),
(2,1,'result2'),
(3,2,'result3'),
(4,2,'result4'),
(5,2,'result5');
First of all crosstab is part of tablefunc, you need to enable it:
CREATE EXTENSION tablefunc;
You need to run it one per database as per this answer.
The final query will look like this:
SELECT *
FROM crosstab(
'SELECT lt.name::TEXT, lt.id, ltr.result
FROM lab_tests AS lt
JOIN lab_tests_results ltr ON ltr.lab_tests_id = lt.id'
) AS ct(test_name text, result_1 text, result_2 text, result_3 text);
Explanation:
The crosstab() function takes a text of a query which should return 3 columns; (1) a column for name of a group, (2) a column for grouping, (3) the value. The wrapping query just selects all the values those crosstab() returns and defines the list of columns after (the part after AS). First is the category name (test_name) and then the values (result_1, result_2). In my query I'll get up to 3 results. If I have more then 3 results then I won't see them, If I have less then 3 results I'll get nulls.
The result for this query is:
test_name |result_1 |result_2 |result_3
---------------------------------------
test1 |result1 |result2 |<null>
test2 |result3 |result4 |result5

I'm trying to insert tuples into a table A (from table B) if the primary key of the table B tuple doesn't exist in tuple A

Here is what I have so far:
INSERT INTO Tenants (LeaseStartDate, LeaseExpirationDate, Rent, LeaseTenantSSN, RentOverdue)
SELECT CURRENT_DATE, NULL, NewRentPayments.Rent, NewRentPayments.LeaseTenantSSN, FALSE from NewRentPayments
WHERE NOT EXISTS (SELECT * FROM Tenants, NewRentPayments WHERE NewRentPayments.HouseID = Tenants.HouseID AND
NewRentPayments.ApartmentNumber = Tenants.ApartmentNumber)
So, HouseID and ApartmentNumber together make up the primary key. If there is a tuple in table B (NewRentPayments) that doesn't exist in table A (Tenants) based on the primary key, then it needs to be inserted into Tenants.
The problem is, when I run my query, it doesn't insert anything (I know for a fact there should be 1 tuple inserted). I'm at a loss, because it looks like it should work.
Thanks.
Your subquery was not correlated - It was just a non-correlated join query.
As per description of your problem, you don't need this join.
Try this:
insert into Tenants (LeaseStartDate, LeaseExpirationDate, Rent, LeaseTenantSSN, RentOverdue)
select current_date, null, p.Rent, p.LeaseTenantSSN, FALSE
from NewRentPayments p
where not exists (
select *
from Tenants t
where p.HouseID = t.HouseID
and p.ApartmentNumber = t.ApartmentNumber
)

t sql select into existing table new column

Hi I have a temp table (#temptable1) and I want to add a column from another temp table (#temptable2) into that, my query is as follows:
select
Customer
,CustName
,KeyAccountGroups
,sum(Weeksales) as Weeksales
into #temptable1
group by Customer
,CustName
,KeyAccountGroups
select
SUM(QtyInvoiced) as MonthTot
,Customer
into #temptalbe2
from SalesSum
where InvoiceDate between #dtMonthStart and #dtMonthEnd
group by Customer
INSERT INTO #temptable1
SELECT MonthTot FROM #temptable2
where #temptable1.Customer = #temptable2.Customer
I get the following: Column name or number of supplied values does not match table definition.
In an INSERT statement you cannot reference the table you are inserting into. An insert works under the assumption that a new row is to be created. That means there is no existing row that could be referenced.
The functionality you are looking for is provided by the UPDATE statement:
UPDATE t1
SET MonthTot = t2.MonthTot
FROM #temptable1 t1
JOIN #temptable2 t2
ON t1.Customer = t2.Customer;
Be aware however, that this logic requires the Customer column in t2 to be unique. If you have duplicate values in that table the query will seem to run fine, however you will end up with randomly changing results.
For more details on how to combine two tables in an UPDATE or DELETE check out my A Join A Day - UPDATE & DELETE post.
If I understand it correctly you want to do two things.
1: Alter table #temptable1 and add a new column.
2: Fill that column with the values of #temptable2
ALTER #temptable1 ADD COLUMN MothTot DATETIME
UPDATE #temptable1 SET MothTot = (
SELECT MonthTot
FROM #temptable2
WHERE #temptable2.Customer = #temptable1.Customer)

use two .nextval in an insert statement

I'm using oracle database and facing a problem where two id_poduct.nextval is creating as error: ORA-00001: unique constraint (SYSTEM.SYS_C004166) violated
It is a primary key. To use all is a requirement. Can I use 2 .nextval in a statement?
insert all
into sale_product values (id_product.nextval, id.currval, 'hello', 123, 1)
into sale_product values (id_product.nextval, id.currval, 'hi', 123, 1)
select * from dual;
insert into sale_product
select id_product.nextval, id.currval, a, b, c
from
(
select 'hello' a, 123 b, 1 c from dual union all
select 'hi' a, 123 b, 1 c from dual
);
This doesn't use the insert all syntax, but it works the same way if you are only inserting into the same table.
The value of id_product.NEXTVAL in the first INSERT is the same as the second INSERT, hence you'll get the unique constraint violation. if you remove the constraint and perform the insert, you'll notice the duplicate values!
The only way is to perform two bulk INSERTS in sequence or to have two seperate sequences with a different range, the latter would require an awful lot of coding and checking.
create table temp(id number ,id2 number);
insert all
into temp values (supplier_seq.nextval, supplier_seq.currval)
into temp values (supplier_seq.nextval, supplier_seq.currval)
select * from dual;
ID ID2
---------- ----------
2 2
2 2
Refrence
The subquery of the multitable insert statement cannot use a sequence
http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9014.htm#i2080134