Unique constraint on SQL insert -ORACLE - sql

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.

Related

Oracle SQL Subquery - Usage of NOT EXISTS

I used a query to find a list of Primary Keys. One Primary key per each ForiegnKey in a table by using below query.
select foreignKey, min(primaryKey)
from t
group by foreignKey;
Let us say this is the result : 1,4,5
NOw I have another table - Table B that has list of all Primary keys. It has 1,2,3,6,7,8,9
I want a write a query using the above query So that I get a subset of the original query(above) that does not exist in Table B. I want 4 and 5 back with the new query.
Use a having clause:
select foreignKey, min(primaryKey)
from t
group by foreignKey
having min(primarykey) not in (select pk from b);
You should also be able to express this as not exists:
having not exists (select 1
from b
where b.pk = min(t.primaryKey)
)

How do I insert data from one table to another when there is unequal number of rows in one another?

I have a table named People that has 19370 rows with playerID being the primary column. There is another table named Batting, which has playerID as a foreign key and has 104324 rows.
I was told to add a new column in the People table called Total_HR, which is included in the Batting table. So, I have to insert that column data from the Batting table into the People table.
However, I get the error:
Msg 515, Level 16, State 2, Line 183 Cannot insert the value NULL into
column 'playerID', table 'Spring_2019_BaseBall.dbo.People'; column
does not allow nulls. INSERT fails. The statement has been terminated.
I have tried UPDATE and INSERT INTO SELECT, however got the same error
insert into People (Total_HR)
select sum(HR) from Batting group by playerID
I expect the output to populate the column Total_HR in the People table using the HR column from the Batting table.
You could use a join
BEGIN TRAN
Update People
Set Total_HR = B.HR_SUM
from PEOPLE A
left outer join
(Select playerID, sum(HR) HR_SUM
from Batting
group by playerID) B on A.playerID = B.playerID
Select * from People
ROLLBACK
Notice that I've put this code in a transaction block so you can test the changes before you commit
From the error message, it seems that playerID is a required field in table People.
You need to specify all required fields of table People in the INSERT INTO clause and provide corresponding values in the SELECT clause.
I added field playerID below, but you might need to add additional required fields as well.
insert into People (playerID, Total_HR)
select playerID, sum(HR) from Batting group by playerID
It is strange, however, that you want to insert rows in a table that should already be there. Otherwise, you could not have a valid foreign key on field playerID in table Batting... If you try to insert such rows from table Batting into table People, you might get another error (violation of PRIMARY KEY constraint)... Unless... you are creating the database just now and you want to populate empty table People from filled/imported table Batting before adding the actual foreign key constraint to table People. Sorry, I will not question your intentions. I personally would consider to update the query somewhat so that it will not attempt to insert any rows that already exist in table People:
insert into People (playerID, Total_HR)
select Batting.playerID, sum(Batting.HR)
from Batting
left join People on People.playerID = Batting.playerID
where People.playerID is null and Batting.playerID is not null
group by playerID
You need to calculate the SUM and then join this result to the People table to bring into the same rows both Total_HR column from People and the corresponding SUM calculated from Batting.
Here is one way to write it. I used CTE to make is more readable.
WITH
CTE_Sum
AS
(
SELECT
Batting.playerID
,SUM(Batting.HR) AS TotalHR_Src
FROM
Batting
GROUP BY
Batting.playerID
)
,CTE_Update
AS
(
SELECT
People.playerID
,People.Total_HR
,CTE_Sum.TotalHR_Src
FROM
CTE_Sum
INNER JOIN People ON People.playerID = CTE_Sum.playerID
)
UPDATE CTE_Update
SET
Total_HR = TotalHR_Src
;

SQL query not returning rows if empty

I am new to SQL and I would like to get some insights for my problem
I am using the following query,
select id,
pid
from assoc
where id in (100422, 100414, 100421, 100419, 100423)
All these id need not have pid, some doesn't and some has pid. Currently it skips the records which doesn't have pid.
I would like a way which would show the results as below.
pid id
-----------
703 100422
313 100414
465 100421
null 100419
null 100423
Any help would be greatly appreciated. Thanks!
Oh, I think I've got the idea: you have to enumerate all the ids and corresponding pids. If there's no corresponding pid, put null (kind of outer join). If it's your case, then Oracle solution can be:
with
-- dummy: required ids
dummy as (
select 100422 as id from dual
union all select 100414 as id from dual
union all select 100421 as id from dual
union all select 100419 as id from dual
union all select 100423 as id from dual),
-- main: actual data we have
main as (
select id,
pid
from assoc
-- you may put "id in (select d.id from dummy d)"
where id in (100422, 100414, 100421, 100419, 100423))
-- we want to print out either existing main.pid or null
select main.pid as pid,
dummy.id as id
from dummy left join main on dummy.id = main.id
id is obtained from other table and assoc only has pid associated with id.
The assoc table seems to be the association table used to implement a many-to-many relationship between two entities in a relational database.
It contains entries only for the entities from one table that are in relationship with entities from the other table. It doesn't contain information about the entities that are not in a relationship and some of the results you want to get come from entities that are not in a relationship.
The solution for your problem is to RIGHT JOIN the table where the column id comes from and put the WHERE condition against the values retrieved from the original table (because it contains the rows you need). The RIGHT JOIN ensures all the matching rows from the right side table are included in the result set, even when they do not have matching rows in the left side table.
Assuming the table where the id column comes from is named table1, the query you need is:
SELECT assoc.id, assoc.pid
FROM assoc
RIGHT JOIN table1 ON assoc.id = table1.id
WHERE table1.id IN (100422, 100414, 100421, 100419, 100423)

DISTINCT ON column only for non null values

How should I declare a query to only use DISTINCT on not null values for certain column but still keep the records for which the column value is null, I'm trying to modify the following query:
I'm trying to modify the following query,
So, basically I want the second query to return all the messages grouped by parent_id when the parent_id column IS NOT NULL and return ALL the records when parent_id IS NULL.
I'm using PG 9.0.4 and Rails 3.1 - any help would be appreciated, thanks!
Select Distinct ON (parent_id) *
from messages
WHERE parent_id IS NOT NULL
UNION
Select * from messages where parent_id IS NULL

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

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.