Updating the parent table considering the values of the child table in oracle - sql

I have table Parent_tbl which consists of 3 columns H_N, Col58 and Type this both the first two columns will be having the same values, only the column type differs.
I have a child table where col58 defines the relationship with the parent but rest of the columns in child_tbl is specific to that table only H_N is the unique column in both of the tables.
I need to update TYPE as EXCHANGE in PARENT_TBL when ever i find the the CHILD_TBL I_STATUS having all the values like S,R and V else the parent_tbl type remains untouched, how can we do this ?
The Parent_tbl.col58 = 1140 that type should be 'EXCHANGE' because child_tbl.col58 = 1140 is having every letter i.e S,R,V.
Here is the DDL for the samples.
CREATE TABLE PARENT_TBL (
H_N number,
col58 number,
TYPE varchar(100)
);
Insert into PARENT_TBL (H_N,COL58,TYPE) values (2,2,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (16,16,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (20,20,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (34,34,'VOID');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (38,38,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (102,102,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (111,111,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (117,117,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (1140,1140,'RETURN');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (131,131,'SALE');
commit;
CREATE TABLE CHILD_TBL
(
I_STATUS varchar(100),
H_n number,
col58 number
);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',3,2);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',5,2);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',7,2);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',8,2);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',10,2);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',1141,1140);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('V',1142,1140);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('R',1143,1140);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('R',1144,1140);
Insert into CHILD_TBL (I_STATUS,H_N,COL58) values ('S',1145,1140);
commit;
EXPECTED OUTPUT:
truncate table PARENT_TBL ;
Insert into PARENT_TBL (H_N,COL58,TYPE) values (2,2,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (16,16,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (20,20,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (34,34,'VOID');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (38,38,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (102,102,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (111,111,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (117,117,'SALE');
Insert into PARENT_TBL (H_N,COL58,TYPE) values (1140,1140,**'EXCHANGE'**);
Insert into PARENT_TBL (H_N,COL58,TYPE) values (131,131,'SALE');

Use this
update PARENT_TBL p
set TYPE='EXCHANGE'
where exists
( select 1
from child_tbl c
where
i_status in ('S','R','V')
and c.col58=p.col58
group by col58
having count(distinct(i_status))=3
)
Explanation:
select col58
from child_tbl c
where
i_status in ('S','R','V')
group by col58
having count(distinct(i_status))=3
This will give you the col58 where count(distinct(i_status))=3 after the filter i_status in ('S','R','V'). So it will be 3 only if there are at least 1 each status of 'S','R','V'. Now use this in exists clause and add
a where condition in the above query and c.col58=p.col58 to join it with the parent table while updating.
Please try this first of your test data and try this without committing the original data. Commit only when you are sure that you got expected result.

Find rows in child table (CHILD_TBL) with proper grouping and use merge:
merge into parent_tbl p
using (select col58
from child_tbl
group by col58
having count(decode(i_status, 'S', 1)) > 0
and count(decode(i_status, 'R', 1)) > 0
and count(decode(i_status, 'V', 1)) > 0) c
on (p.col58 = c.col58)
when matched then update set type = 'EXCHANGE'

Related

SQL Server: Split Data in a column based on a delimiter and then join with reference table to get ID values associated

I would like to achieve the column Expected in the screenshot below. Could you please help me achieve this on Synapse Datawarehouse using the following table scripts and sample data.
Note:
This is just a sample data set. The original Users table would have millions of rows.
Users column can more than N number of users separated with delimiter ';'
CREATE TABLE [BTS_Test].[Users]
(
[Date] [date] NOT NULL,
[Users] [varchar](500) NOT NULL
)
WITH
(
DISTRIBUTION = ROUND_ROBIN
);
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Rupesh; Suresh; Yogesh');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Anne; Prudvi; Mahesh');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Bobby');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Crystal; Abella');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-11','Balaji; Kishan; Silpa; Sindhu Srinivas; Kiran');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-12','Cindrella');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-12','Monika; Chandler');
INSERT INTO [BTS_Test].[Users] VALUES('2023-01-13','Niko Paul');
CREATE TABLE [BTS_Test].[Student]
(
[ID] [int] NOT NULL,
[StudentName] [varchar](500) NOT NULL
)
WITH
(
DISTRIBUTION = REPLICATE
);
INSERT INTO [BTS_Test].[Student] VALUES(1,'Rupesh');
INSERT INTO [BTS_Test].[Student] VALUES(2,'Suresh');
INSERT INTO [BTS_Test].[Student] VALUES(3,'Yogesh');
INSERT INTO [BTS_Test].[Student] VALUES(4,'Anne');
INSERT INTO [BTS_Test].[Student] VALUES(5,'Prudvi');
INSERT INTO [BTS_Test].[Student] VALUES(6,'Mahesh');
INSERT INTO [BTS_Test].[Student] VALUES(7,'Bobby');
INSERT INTO [BTS_Test].[Student] VALUES(8,'Crystal');
INSERT INTO [BTS_Test].[Student] VALUES(9,'Abella');
INSERT INTO [BTS_Test].[Student] VALUES(10,'Balaji');
INSERT INTO [BTS_Test].[Student] VALUES(11,'Kishan');
INSERT INTO [BTS_Test].[Student] VALUES(12,'Silpa');
INSERT INTO [BTS_Test].[Student] VALUES(13,'Sindhu Srinivas');
INSERT INTO [BTS_Test].[Student] VALUES(14,'Kiran');
INSERT INTO [BTS_Test].[Student] VALUES(15,'Cindrella');
INSERT INTO [BTS_Test].[Student] VALUES(16,'Monika');
INSERT INTO [BTS_Test].[Student] VALUES(17,'Chandler');
INSERT INTO [BTS_Test].[Student] VALUES(18,'Niko Paul');
Here is an option using JSON to keep the sequence. Performance over millions of rows??? Just keep in mind there are penalties for storing delimited data.
Example
Select *
From [Users] A
Cross Apply (
Select Expected = string_agg(ID,';') WITHIN GROUP ( ORDER BY [key] )
From OpenJSON( '["'+replace(string_escape([Users],'json'),';','","')+'"]' )
Join [Student] on trim(Value)=StudentName
) B
Results
Date Users Expected
2023-01-11 Rupesh; Suresh; Yogesh 1;2;3
2023-01-11 Anne; Prudvi; Mahesh 4;5;6
2023-01-11 Bobby 7
2023-01-11 Crystal; Abella 8;9
2023-01-11 Balaji; Kishan; Silpa; Sindhu Srinivas; Kiran 10;11;12;13;14
2023-01-12 Cindrella 15
2023-01-12 Monika; Chandler 16;17
2023-01-13 Niko Paul 18
This produces results using STRING_SPLIT and XML:
SELECT u.[DATE], u.USERS, (STUFF((SELECT ';' + Y
FROM (select CAST(s.id AS VARCHAR) AS y from STRING_SPLIT (u.USERS, ';') sp
INNER JOIN STUDENT s on s.STUDENTNAME = trim(sp.Value)) X
FOR XML PATH('')) ,1,1,'')) as EXPECTED
FROM USERS u

Finding trouble in generating the list of all Students who belongs to the major named as “CS” but not to major named as “EE”

S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Create table Students(
S_id int Primary Key,
S_name varchar(100),
Gpa float ,
Size_hs int
)
Create table Apply (
s_id int ,
C_name varchar(100),
Major varchar(10),
Decision varchar(2)
)
insert into Students values (123,'Amy',3.9,1000)
insert into Students values (234,'Bob',3.6,1500)
insert into Students values (345,'Craig',3.5,500)
insert into Students values (456,'Doug',3.9,1000)
insert into Students values (567,'Edward',2.9,2000)
insert into Students values (678,'Fay',3.8,200)
insert into Students values (789,'Gray',3.4,800)
insert into Students values (987,'Helen',3.7,800)
insert into Students values (876,'Irene',3.9,400)
insert into Students values (765,'Jay',2.9,1500)
insert into Students values (654,'Amy',3.9,1000)
insert into Students values (543,'Craig',3.4,2000)
insert into Apply values (123,'NJIT','CS','Y')
insert into Apply values (123,'NJIT','EE','N')
insert into Apply values (123,'Stoony Brook','CS','Y')
insert into Apply values (123,'Cornell','EE','Y')
insert into Apply values (234,'Stoony Brook','Bio','N')
insert into Apply values (345,'WPI','Bio-Eng','Y')
insert into Apply values (345,'Cornell','Bio-Eng','N')
insert into Apply values (345,'Cornell','CS','Y')
insert into Apply values (345,'Cornell','EE','N')
insert into Apply values (678,'NJIT','Hist','Y')
insert into Apply values (987,'NJIT','CS','Y')
insert into Apply values (987,'Stoony Brook','CS','Y')
insert into Apply values (876,'NJIT','Bio','N')
insert into Apply values (876,'WPI','Marine-Bio','Y')
insert into Apply values (876,'WPI','Hist','N')
insert into Apply values (765,'NJIT','Hist','Y')
insert into Apply values (765,'Cornell','Hist','N')
insert into Apply values (765,'Cornell','Psych','Y')
insert into Apply values (543,'WPI','CS','N')
Basically I have to find the list of students id who belongs to major named as 'Cs' but not to the major 'EE'. I tried it by myself but it is not working properly.
Here is the code below:
select * from students
where s_id in (
select s_id
from apply
where major='CS' and Major!='EE'
group by s_id
)```
I would use exists and not exists:
select s.*
from students s
where
exists (select 1 from applies a where a.s_id = s._id and a.major = 'CS')
and not exists (select 1 from applies a where a.s_id = s._id and a.major = 'EE')
With an index on applies(s_id, major), this should be an efficient option.
Another approach is to join, aggregate, and filter with a having clause. This requires listing the columns that you want to show in both the select and group by clauses:
select s.s_id, s.s_name
from students s
inner join applies a on a.s_id = s.s_id
where a.major in ('CS', 'EE')
group by s.s_id, s.s_name
having
max(case when a.major = 'CS' then 1 else 0 end) = 1
and max(case when a.major = 'EE' then 1 else 0 end) = 0
Note: apply is a reserved word in a number a databases (SQL Serer, Oracle, ...), hence not a good choice for a table name. I renamed it to applies in the queries.

SQL selecting records with view

How to solve this?
I have a tables A,B,C and view from C
Table A has a1,a2,a3 etc.
Table C has c1,c2,c3 etc.
Table B has
(a1,c1)
(a1,c4)
(a1,c3)
(a2,c1)
(a2,c3)
(a2,c4)
(a3,c1)
(a3,c4)
(a4,c1)
(a4,c4)
(a4,c3)
(a4,c5)
Examples:
I have View C with c1,c3,c4
Result should be: a1, a2, a4
Or:
View C: c1, c5
Result should be: a4
I want all the elements (aX) from table B that have all the elements in the view C.
You could do it like this:
create table temp_a (
a_rec varchar2(2)
);
create table temp_b (
a_rec varchar2(2),
c_rec varchar2(2)
);
create table temp_c (
c_rec varchar2(2)
);
insert into temp_a values ('a1');
insert into temp_a values ('a2');
insert into temp_a values ('a3');
insert into temp_a values ('a4');
insert into temp_c values ('c1');
insert into temp_c values ('c3');
insert into temp_c values ('c4');
insert into temp_b values ('a1','c1');
insert into temp_b values ('a1','c4');
insert into temp_b values ('a1','c3');
insert into temp_b values ('a2','c1');
insert into temp_b values ('a2','c3');
insert into temp_b values ('a2','c4');
insert into temp_b values ('a3','c1');
insert into temp_b values ('a3','c4');
insert into temp_b values ('a4','c1');
insert into temp_b values ('a4','c4');
insert into temp_b values ('a4','c3');
insert into temp_b values ('a4','c5');
select b.a_rec
from temp_b b
join temp_c c on c.c_rec = b.c_rec
group by a_rec
having count(*) >= (select count(c_rec) from temp_c);
Note that if you have View C with c1,c3,c4, then the result will actually be: a1, a2, a4 (since a1 also meets the criteria).

insert data to temporary table in sql 2008

CREATE TABLE #tmpt
(
ID INT
,sName varchar(20)
)
INSERT INTO #tmpt VALUES (1,'ran')
INSERT INTO #tmpt VALUES (2,'pan')
INSERT INTO #tmpt VALUES (3,'fan')
INSERT INTO #tmpt VALUES (4,'gan')
This type of insert does not work. Can you help

Flattening a table that contains rows that reference other rows in SQL Server 2005

I am facing a problem that occasionally comes up when you deal with not fully normalized table. Here is the problem. Imagine a table with 4 columns, and let's call this table dbo.Hierarchical. Here is the definition of the table:
if OBJECT_ID('dbo.Hierarchical') is not null
drop table dbo.Hierarchical
create table dbo.Hierarchical
(
colID int not null identity(1,1) primary key
,GroupName varchar(5) not null
,IsAtomic bit not null
,Constituent varchar(5) null
)
This table can have a GroupName that is Atomic, which means that it doesn not have a component, or can not be Atomic. In this case, a GroupName can contain other GroupNames.
Lets fill the table with some data for clarity.
set nocount on
insert into dbo.Hierarchical values ('A',0,'B')
insert into dbo.Hierarchical values ('A',0,'C')
insert into dbo.Hierarchical values ('B',1,'B')
insert into dbo.Hierarchical values ('C',0,'K')
insert into dbo.Hierarchical values ('C',0,'L')
insert into dbo.Hierarchical values ('D',0,'E')
insert into dbo.Hierarchical values ('D',0,'F')
insert into dbo.Hierarchical values ('D',0,'G')
insert into dbo.Hierarchical values ('E',1,'E')
insert into dbo.Hierarchical values ('F',1,'F')
insert into dbo.Hierarchical values ('G',0,'H')
insert into dbo.Hierarchical values ('G',0,'I')
insert into dbo.Hierarchical values ('H',1,'H')
insert into dbo.Hierarchical values ('I',1,'I')
insert into dbo.Hierarchical values ('J',1,'J')
insert into dbo.Hierarchical values ('K',1,'K')
insert into dbo.Hierarchical values ('L',1,'L')
insert into dbo.Hierarchical values ('M',1,'M')
insert into dbo.Hierarchical values ('N',1,'N')
set nocount off
Now if we look at a simple select * from dbo.Hierarchical we get the following:
GroupName colID IsAtomic Constituent
A 1 0 B
A 2 0 C
B 3 1 B
C 4 0 K
C 5 0 L
D 6 0 E
D 7 0 F
D 8 0 G
E 9 1 E
F 10 1 F
G 11 0 H
G 12 0 I
H 13 1 H
I 14 1 I
J 15 1 J
K 16 1 K
L 17 1 L
M 18 1 M
N 19 1 N
Whew, that was long winded. Now, notice that the first two rows have GroupName A and Constiuents B and C. B is Atomic, so it has no further constiuents. C, however, has constiuents K, L (K and L are Atomic). How can I create a view that will flatten this table out so that I only see GroupName and the Atomic constiuents. In the case of GroupName A, I shoud see 3 rows
A B
A K
A L
give this a try:
--just a repeat of OP's original table and data
DECLARE #Hierarchical table
( colID int not null identity(1,1) primary key
,GroupName varchar(5) not null
,IsAtomic bit not null
,Constituent varchar(5) null)
set nocount on
insert into #Hierarchical values ('A',0,'B');insert into #Hierarchical values ('A',0,'C');
insert into #Hierarchical values ('B',1,'B');insert into #Hierarchical values ('C',0,'K');
insert into #Hierarchical values ('C',0,'L');insert into #Hierarchical values ('D',0,'E');
insert into #Hierarchical values ('D',0,'F');insert into #Hierarchical values ('D',0,'G');
insert into #Hierarchical values ('E',1,'E');insert into #Hierarchical values ('F',1,'F');
insert into #Hierarchical values ('G',0,'H');insert into #Hierarchical values ('G',0,'I');
insert into #Hierarchical values ('H',1,'H');insert into #Hierarchical values ('I',1,'I');
insert into #Hierarchical values ('J',1,'J');insert into #Hierarchical values ('K',1,'K');
insert into #Hierarchical values ('L',1,'L');insert into #Hierarchical values ('M',1,'M');
insert into #Hierarchical values ('N',1,'N');set nocount off
--declare and set starting position
DECLARE #Start varchar(5)
SET #Start='A'
--get the data
;WITH HierarchicalTree AS
(
SELECT
GroupName, Constituent, 1 AS LevelOf
FROM #Hierarchical
WHERE GroupName=#Start
UNION ALL
SELECT
t.GroupName, h.Constituent, t.LevelOf+1
FROM HierarchicalTree t
INNER JOIN #Hierarchical h ON t.Constituent=h.GroupName
WHERE h.Constituent!=h.GroupName AND h.IsAtomic=0
)
SELECT
t.GroupName,t.Constituent
FROM HierarchicalTree t
INNER JOIN #Hierarchical h ON t.Constituent=h.GroupName
WHERE h.IsAtomic=1
OUTPUT:
GroupName Constituent
--------- -----------
A B
A K
A L
(3 row(s) affected)
Well this does what you have asked for but it will only work if it's nested once. If you need recursion then you would have to use a CTE.
select a.GroupName,
b.Constituent
From dbo.Hierarchical a
Left Join dbo.Hierarchical b on a.Constituent = b.GroupName
Is this what you need or have I missed the point completely?
For the sake of completeness, I've attached the entire sql script file that setups up the problem and shows the solution. Again, Hattip to KM.
use tempdb
go
if OBJECT_ID('dbo.Hierarchical') is not null
drop table dbo.Hierarchical
create table dbo.Hierarchical
(
colID int not null identity(1,1) primary key
,GroupName varchar(5) not null
,IsAtomic bit not null
,Constituent varchar(5) null
)
set nocount on
insert into dbo.Hierarchical values ('A',0,'B')
insert into dbo.Hierarchical values ('A',0,'C')
insert into dbo.Hierarchical values ('B',1,'B')
insert into dbo.Hierarchical values ('C',0,'K')
insert into dbo.Hierarchical values ('C',0,'L')
insert into dbo.Hierarchical values ('D',0,'E')
insert into dbo.Hierarchical values ('D',0,'F')
insert into dbo.Hierarchical values ('D',0,'G')
insert into dbo.Hierarchical values ('E',1,'E')
insert into dbo.Hierarchical values ('F',1,'F')
insert into dbo.Hierarchical values ('G',0,'H')
insert into dbo.Hierarchical values ('G',0,'I')
insert into dbo.Hierarchical values ('H',1,'H')
insert into dbo.Hierarchical values ('I',1,'I')
insert into dbo.Hierarchical values ('J',1,'J')
insert into dbo.Hierarchical values ('K',1,'K')
insert into dbo.Hierarchical values ('L',1,'L')
insert into dbo.Hierarchical values ('M',1,'M')
insert into dbo.Hierarchical values ('N',1,'N')
set nocount off
-- see what the over nomalized table looks like
-- before you call the CTE. Notice how A has
-- Constiuents B, and C. And further down
-- C is made up of K, and L.
-- select * from dbo.Hierarchical
go
-- Use the CTE to
;WITH HierarchicalTree AS
(
SELECT
GroupName, Constituent, 1 AS LevelOf
FROM dbo.Hierarchical
--WHERE GroupName=#Start
UNION ALL
SELECT
t.GroupName, h.Constituent, t.LevelOf+1
FROM HierarchicalTree t
INNER JOIN dbo.Hierarchical h ON t.Constituent=h.GroupName
WHERE h.Constituent!=h.GroupName AND h.IsAtomic=0
)
-- Now, notice this query will give us A with the it's
-- Constiuent elements B, K, and L
SELECT
t.GroupName,t.Constituent, h.IsAtomic, t.LevelOf
FROM HierarchicalTree t
INNER JOIN dbo.Hierarchical h ON t.Constituent=h.GroupName
--WHERE h.IsAtomic=1
Where h.Constituent = h.GroupName
order by
t.GroupName
if OBJECT_ID('tempdb..Hierarchical') is not null
drop table dbo.Hierarchical