How can I SELECT DISTINCT on one (excluded) column, but include other columns in the query? (ORACLE) - sql

So I have data arranged loosely like this:
Table 1 - PEOPLE: person_id (primary key), parent_id, child_id, other_parent_fields, other_child_fields
Table 2 - PARENTS: parent_id (auto incrementing primary key), other_fields
Table 3 - CHILDREN: child_id (auto incrementing primary key), parent_id(foreign key referencing PARENTS) other_fields
I want to be able to query for all of the distinct parents from the PEOPLE table, and insert all of the other_parent_fields into the PARENTS table, throwing out the old parent_id from Table 1, in favor of my auto incrementing parent_id in table 2.
I also want to do the same for children, but maintain the parent-child relationships, only using my own ids from table 2 and table 3.
Essentially, I am trying to change the way that the database is designed. Rather than a whole table for all people, I am creating a PARENTS table and a CHILDREN table, the latter of which refers to PARENTS with a foreign key. The reason I am throwing out the ids from table 1 is because I have no reason to care about them in my new table (i.e. the numbering can start back from one, and additional entries can just auto increment the primary key). However, before discarding these IDs from table 1, I need to capture the parent-child relations that they relay.
Is this even possible? How would one go about doing it?
we can assume, for simplicity that no children have children i.e. someone cant be a parent and a child

I did not fully understand your question but it seems that you first query would be this (SQL Server syntax):
insert into Parents
select other_parent_fields, person_id as legacy_parent_id
from (select distinct person_id, other_parent_fields from PEOPLE where parent_id is null) x
The trick would be to first group on parent_id, other_parent_fields and then discard the parent_id. (A distinct is equal to a group by *). The above query only works if other_parent_fields is a pure function of parent_id. I interpret your question as an attempt to normalize denormalized data, so I guess this is true.
In order to extract the children you can do this:
insert into Children
select other_child_fields, parent_id as legacy_parent_id
from (select distinct person_id, other_child_fields from PEOPLE where parent_id is not null) x
Now your tables contain the distinct parents and children as well as their old IDs. You have to write an update query now that assigns the new parent ids into the children table. Then you drop the legacy fields.

Related

Oracle SQL - need to flip values, but don't know how

select kasutaja_nimi, eesnimi, perenimi, r_nimetus, seeria_nr, max(paigalduse_aeg) as paigaldus
from kasutaja ka
right join riistvara ri on ka.id = ri.id
right join r_paigaldus r on ka.id = r.kasutaja_id
group by kasutaja_nimi, eesnimi, perenimi, seeria_nr, r_nimetus;
This is the output, but I need those values changed. I have ID primary keys for both - kasutaja and riistvara, but I don't know how to match kasutaja ID 1 with riistvara ID 2 and vice versa.
And the output should be like this:
The R_NIMETUS and SEERIA_NR fields are different on my output what I get with my code.
you can't cross the data because you haven't a logic link between two tables.
You have only one solution, you must change your table structure:
Scenario 1
If you have a parent - child relation, please add a foreign key on child table
Scanerio 2
If you have a n:m relationship, please create a middle table with fks to parent and child table.
So in your query you can use JOIN operations to show correctly your results

Removing row when only a single specific relationship exists

I have a table person with a uid and an email. I also have a table parent_child where I store parental relationships. It has parent_uid and child_uid, which are both required references to the uid of the person table.
When I delete a person, I want to delete all children as long as:
The child does not have an email set. I'm just checking for an # sign for this due to how I use this field in other places.
The child does not have any other parents.
Right now I'm trying to do this, from a BEFORE DELETE ON person trigger, but I'm feeling like it's not the most efficient way to handle this.
FOR child IN SELECT DISTINCT child_uid FROM parent_child WHERE parent_uid = OLD.uid
LOOP
IF NOT EXISTS (
-- Any parent that is not me.
SELECT 1
FROM parent_child
WHERE child_uid = child AND parent_uid <> OLD.uid
) THEN
DELETE FROM person WHERE uid = child AND email NOT LIKE '%#%'
END IF;
END LOOP;
There is no better way to do this than a trigger.
You would index person(uid), parent(parent_uid) and parent_child(child_uid) for efficiency (one of the latter indexes should be unnecessary, because you'll have a primary key constraint on parent_uid and child_uid).

Simple SQL statement with parent/child hierarchies

It's been a while since I've needed to write SQL statements (and I don't even know if ever had enough knowledge to make this statement).
So, here's the deal. Table has two column. One is for parent id, other is for child Id.
parent_id | child_id
4 | 2
2 | 5
This is simply for saving composite parent/child hierarchies.
4, 2 line means that structure with id 4 refers to structure id 2 as a child.
2, 5 means structure with id 2 refers to structure with id 5 as a child.
And so on.
This is what I need to do:
I need to extract ALL structures, that are not referenced by any structure as a child (root structures).
What SQL (preferrably postgres) statement will accomplish that?
Finding all structures that are not a child of another structure:
select *
from YourTable
where Parent_Id not in (Select child_id from ...)
Assuming there is no scope for a grandparent, great-grandparent relationsips, I would recommend use a Left-JOIN in this case.
Somethink on the lines of:
Select * from Table
LEFt join Table on Parent_id=child_id
WHERE child_id is null
SELECT *
FROM structures
WHERE id not in ( SELECT child_id FROM Table ) AS dummy

Unique constraint on SQL insert -ORACLE

Im running a script which would fire a select query and insert the results into a table.
The select query is
select distinct a.child child_id, a.parent parent_id from cat a, par b WHERE a.child=b.catentid and b.catenttype_id='Product' and a.reltype_id='PRODUCT_ITEM'
and inserted into the table which is created as
create table TI_CAT_0 ( child_id NUMBER not null,parent_id NUMBER not null,PRIMARY KEY (child_id))
But I get a unique key constraint violation while running the script as "SYS_C00187123", and I checked this constraint name in all_constraints table and its on the TI_CAT_0 table only.
Since I use the distinct command, I'm not sure why this violation is turning up. Its a Oracle DB.
Assuming you are creating the TI_CAT_0 table from scratch and inserting records from your SELECT query, then you are either unintentionally inserting the same record more than once, or your initial query is returning multiple rows for each child_id. If this is the case, you should run this query to see if your initial query is returning duplicate child_id values. Your query, as it is written, will return unique combinations of child_id and parent_id. You can check to see if multiple parents are associated with a single child with the following SQL:
select
a.child,
count(a.parent) as parent_count
from
cat a
join par b
on a.child = b.catentid
where
b.catenttype_id='Product'
and a.reltype_id='PRODUCT_ITEM'
group by
a.child
having
count(a.parent) > 1
order by 2 desc
The results (if any) will be all child_id values associated with multiple parent_id values.

Nested query using while condition - sql

I need to do a nested query on a single table. Each row is potentially the parent or child of another row.
Is it possible to do this with a single select statement? Ive started using this statement but it only goes down one level.
select * from myTable where parent_id in
(select id from myTable where name = 'manager' )
This select however will only go down one level. If a row has multiple children they will be ignored. (In the table each row has an Id field , if a row has a parent then the parents Id value will be in the child's parent_Id field. )
If i could include a while loop in the SQL which would always check to see if the returned Id was a parent or not and if it was check and see if any other row was its child by checking the other rows parent_Id. However i m concerned this would take alot of cycles to eventually find all parent child relationships. Any suggestions? Thanks
using Oracle db
I think you are looking for a hierarchical query like this:
select * from mytable
connect by prior id = parent_id
start with name = 'Manager';
(A "nested table" is something else entirely.)