Insert columns into rows for each ID - sql

I have two tables:
table 1:
ID name
--------- -----------
1 john
2 salma
3 tony
table2:
ID Tasks amount
--------- ----------- ----------
1 write 2
1 memorize 3
1 read 6
1 sing NULL
2 write 1
2 memorize NULL
2 read 5
2 sing NULL
3 write NULL
3 memorize 8
3 read 2
3 sing NULL
I want to insert new columns in table1 for each task mentioned in table2.
Table1:
ID name write memorize read sing
--------- ----------- -------- --------- ------- --------
1 john 2 3 6 NULL
2 salma 1 NULL 5 NULL
3 tony NULL 8 2 NULL
I can do the insert in Table1 for one ID at a time, but not for all of them. Thanks in advance!

First, I inserted the row values in a temporary table as columns using pivot:
select * into #Results
from
(
select ID,Tasks,amount
from #Table2
) tb2
pivot
(
max(amount)
for ID in ([1], [2], [3])
) as piv
Then, I did an inner join with Table1:
select * from Table1 tb1 inner join #Results r on r.ID =tb1.ID
Thanks #JamesL for the seggustion to use pivot!

Related

I have this small table having duplicate id and names and I want to replace null values with names using there ID

I got it with self join:
select a.id, a.name, b.id, b.name, nvl(a.name,b.name)
from names a
join names b
on a.id = b.id
where a.name is null and b.name is not null;
But don't no how do I update it in the table.
I tried update statement but did not work
[]
Problem is that there are no unique [id, name] combinations in rows that don't have empty name columns.
SQL> select * From test;
ID NAME
---------- ------
1 naya
1 naya
2 amar
3 dhruv --> here
4 shyla
4 shyla
3 diya --> here
5 ananya
6 ishaan
5
2
2
1
3
14 rows selected.
SQL>
So, which name would you want to get for ID = 3? You can't have both, so - one option is to select any, e.g. max.
SQL> update test a set
2 a.name = (select max(b.name)
3 from test b
4 where b.id = a.id
5 )
6 where a.name is null;
5 rows updated.
Result:
SQL> select * From test;
ID NAME
---------- ------
1 naya
1 naya
2 amar
3 dhruv
4 shyla
4 shyla
3 diya
5 ananya
6 ishaan
5 ananya
2 amar
2 amar
1 naya
3 diya
14 rows selected.
SQL>
From Oracle 12, you can use:
UPDATE names n
SET name = (SELECT name
FROM names x
WHERE x.id = n.id
ORDER BY name NULLS LAST
FETCH FIRST ROW ONLY)
WHERE name IS NULL
db<>fiddle here

SQL concat function, combine size and colour

If there is a table called variant
id slug slug_id
------- --------- ----------
1 s 10
1 m 10
1 l 10
1 black 11
1 pink 11
1 ship_us 12
1 ship_uk 12
2 xl 10
2 xxl 10
2 blue 11
2 white 11
Result I need in this format:
id variant_slug
-------- ------------
1 1-s-black-ship_us
1 1-s-black-ship_uk
1 1-s-pink-ship_us
1 1-s-pink-ship_uk
1 1-m-black-ship_us
1 1-m-black-ship_uk
1 1-m-pink-ship_us
1 1-m-pink-ship_uk
1 1-l-black-ship_us
1 1-l-black-ship_uk
1 1-l-pink-ship_us
1 1-l-pink-ship_uk
2 2-xl-blue
2 2-xl-white
2 2-xxl-blue
2 2-xxl-white
Q: this record is in same variant table. I have almost no experience using UDFs, stored procedures, I need to be done this thing through query. Is this possible without using UDFs, SP's.
Perhaps a self-join assuming the length of size<=3.
Select A.ID
,variant_slug = concat(A.id,'-',A.slug,'-',B.slug)
from YourTable A
Join YourTable B
on A.ID=B.ID
and A.slug<>B.slug
and len(B.slug)>3
and len(A.slug)<=3
Results
ID variant_slug
1 1-l-black
1 1-l-pink
1 1-m-black
1 1-m-pink
1 1-s-black
1 1-s-pink
2 2-xl-blue
2 2-xl-white
2 2-xxl-blue
2 2-xxl-white
Rather than len(), you can enumerate the sizes i.e. {NOT } IN ('s','m','l','xl','xxl')
Select A.ID
,variant_slug = concat(A.id,'-',A.slug,'-',B.slug)
from YourTable A
Join YourTable B
on A.ID=B.ID
and A.slug<>B.slug
and B.slug NOT IN ('s','m','l','xl','xxl')
and A.slug IN ('s','m','l','xl','xxl')
You can go for INNER JOIN by separating the table into two separate tables: size, color and get the variant data, as given below:
declare #slug table(id int, slug varchar(100))
insert into #slug values
(1,'s')
,(1,'m')
,(1,'l')
,(1,'black')
,(1,'pink')
,(2,'xl')
,(2,'xxl')
,(2,'blue')
,(2,'white');
SELECT size.id, CONCAT_WS('-',size.id,size.size, color.color) as variant_size
from (select id,slug as size from #slug where slug in ('s','m','l','xl','xxl') ) as size
INNER JOIN (select id,slug as color from #slug where slug NOT in ('s','m','l','xl','xxl') ) as COLOR
on color.id = size.id
id
variant_size
1
1-s-black
1
1-s-pink
1
1-m-black
1
1-m-pink
1
1-l-black
1
1-l-pink
2
2-xl-blue
2
2-xl-white
2
2-xxl-blue
2
2-xxl-white

How to compare each group of one table with a column in another table?

I have two tables:
TypeTable
TypeId PersonClassificationId
----------------------
1 1
1 2
1 3
2 1
2 2
PersonClassificationTable
PersonClassificationId Capacity
----------------------
1 2
2 2
3 2
I need to select such TypeId that in the entire TypeTable table do not have at least one PersonClassificationID specified in PersonTable.
So, if PersonTable has 1, 2, 3, then TypeId = 2 should be selected, because there is no record in TypeTable:
TypeId PersonClassificationId
----------------------
2 3
How can I do that?
It is undesirable to use cursors : )
I think that you can do what you want by generating all possible combinations of types and classifications, and then filter on those that do not exist in the mapping table:
select t.TypeId, pc.PersonClassificationId
from (select distinct TypeId from TypeTable) t
cross join PersonClassificationTable p
where not exists (
select 1
from TypeTable t1
where t1.TypeId = t.TypeId and t1.PersonClassificationId = p.PersonClassificationId
)

Left joining multiple tables with select statements and aliases

I'm doing a db2 stored procedure where I'm left joining multiple tables into a new table and adding tablename as a prefix to all column names. Running into a lot of obstacles and I could use some help structuring this statement. See an example of what I'm trying to do below. Does anyone have suggestions on how to do this?
CREATE TABLE <new_table> AS
SELECT * FROM (
SELECT t1.<column1> AS t1.<table1>_<column1>, t1.<column2> AS t1.<table1>_<column2> , ... FROM <table1> t1
LEFT JOIN
(SELECT <column1> AS <table2>_<column1>, <column2> AS <table2>_<column2> , ... FROM <table2>) t2
ON t2.<table2>_<column2> = t1.<table1>_<column1>
LEFT JOIN
(SELECT <column1> AS <table3>_<column1>, <column2> AS <table3>_<column2> , ... FROM <table3>) t3
ON t2.<table2>_<column1> = t3.<table3>_<column1>
);
When your column names include periods or special characters you will always need to double-quote the column names when they are used in SQL or DDL. This is sometimes painful.
The example below is for Db2-LUW V11.1.3.3 or higher:
create table thom.o1 (a integer, b integer);
create table thom.o2 (a integer, b integer);
create table thom.o3 (a integer, b integer);
insert into thom.o1(a,b) values(1,2);
insert into thom.o2(a,b) values(1,4),(1,3),(1,5),(2,9);
insert into thom.o3(a,b) values(1,6),(1,7),(1,8),(3,10);
create table thom.new_tab as (
select t1.a as "t1.o1.a"
,t1.b as "t1.o1.b"
,t2.a as "t2.o2.a"
,t2.b as "t2.o2.b"
,t3.a as "t3.o3.a"
,t3.b as "t3.o3.b"
from thom.o1 t1
left join thom.o2 t2
on t1.a = t2.a
left join thom.o3 t3
on t2.a = t3.a
) with data
;
describe table thom.new_tab;
Data type Column
Column name schema Data type name Length Scale Nulls
------------------------------- --------- ------------------- ---------- ----- ------
t1.o1.a SYSIBM INTEGER 4 0 Yes
t1.o1.b SYSIBM INTEGER 4 0 Yes
t2.o2.a SYSIBM INTEGER 4 0 Yes
t2.o2.b SYSIBM INTEGER 4 0 Yes
t3.o3.a SYSIBM INTEGER 4 0 Yes
t3.o3.b SYSIBM INTEGER 4 0 Yes
6 record(s) selected.
select * from thom.new_tab ;
select * from thom.new_tab
t1.o1.a t1.o1.b t2.o2.a t2.o2.b t3.o3.a t3.o3.b
----------- ----------- ----------- ----------- ----------- -----------
1 2 1 4 1 6
1 2 1 5 1 6
1 2 1 3 1 6
1 2 1 4 1 7
1 2 1 5 1 7
1 2 1 3 1 7
1 2 1 4 1 8
1 2 1 5 1 8
1 2 1 3 1 8
9 record(s) selected.

How to apply Joins in Oracle to require result

I have Following 3 tables :
SHIFT_MASTER,PATTERN_MASTER,PATTERN_DETAILS
S_ID ,P_ID,P_D_ID are the priamry keys of SHIFT_MASTER,PATTERN_MASTER,PATTERN_DETAILS tables respectively.
SHIFT_MASTER
S_ID | S_NUMBER| S_Name
---------------------------------
1 A MORNING
2 B AFTERNOON
3 C NIGHT
PATTERN_MASTER
P_ID | P_NAME
----------------
1 Pattern 1
2 Pattern 2
PATTERN_DETAILS
P_D_ID|P_ID | S_ID| ...
---------------------
1 1 1
2 1 2
3 1 3
4 1 2
5 1 1
6 2 3
7 2 2
8 2 1
9 2 3
I GOT OUTPUT AS
P_ID | S_ID
1 1,2,3,2,1
2 3,2,1,3
USING QUERY
SELECT PATTERN_DETAILS.P_ID "PATTERN",
LISTAGG(PATTERN_DETAILS.S_ID, ', ')
WITHIN GROUP (ORDER BY PATTERN_DETAILS.P_D_ID) "SHIFT"
FROM PATTERN_DETAILS
GROUP BY PATTERN_DETAILS.P_ID;
WHAT I WANT IS
P_NAME | S_NUMBER
Pattern 1 A,B,C,B,A
Pattern 2 C,B,A,C
Any suggestion ??? Instead of P_ID i want to show pattern name and instead of shift id i want to show shift number .How to perform join operation along with listagg function ?
You need to join all three tables to get this,
SELECT pm.p_name "P_NAME",
listagg(sm.s_number, ', ') WITHIN GROUP (ORDER BY pd.p_d_id) "S_NUMBER"
FROM pattern_master pm,
pattern_details pd,
shift_master sm
WHERE sm.s_id= pd.s_id
AND pm.p_id = pd.p_id
GROUP BY pm.p_name;