Joining multiple rows into a single row without aggregation using Oracle11g - sql

The below link shows the same question that was asked which I want to ask and the code which was provided to answer the query, I used this query (modified it) but please how do I add a join table and a where clause in this query? see below the code I have added to the code in the link below but I am getting error messages. I would like the output to be same as the one provided in the link below
Joining multiple rows into a single row without aggregation [Oracle]
Bare in mind that the desired result provided in the link is my same desired results.
Below is the script which I have modified:
select max(case when seqnum = 1 then p.PERSONID end) as PersonID,
max(case when seqnum = 1 then t.PHONEID end) as PhoneID1,
max(case when seqnum = 1 then t.PHONENUM end) as PhoneNum1,
max(case when seqnum = 1 then t.TYPE end) as Type1,
max(case when seqnum = 1 then t.ISPRIMARY end) as IsPrimary1,
max(case when seqnum = 1 then t.ROWSTAMP1 end) as Rowstamp1,
max(case when seqnum = 2 then t.PHONEID end) as PhoneID2,
max(case when seqnum = 2 then t.PHONENUM end) as PhoneNum2,
max(case when seqnum = 2 then t.TYPE end) as Type2,
max(case when seqnum = 2 then t.ISPRIMARY end) as IsPrimary2,
max(case when seqnum = 2 then t.ROWSTAMP1 end) as Rowstamp2,
max(case when seqnum = 3 then t.PHONEID end) as PhoneID3,
max(case when seqnum = 3 then t.PHONENUM end) as PhoneNum3,
max(case when seqnum = 3 then t.TYPE end) as Type3,
max(case when seqnum = 3 then t.ISPRIMARY end) as IsPrimary3,
max(case when seqnum = 3 then t.ROWSTAMP1 end) as Rowstamp3
from (test1.phone t left join test2.person p
ON t1.PERSONID = t2.PERSONID
where t2.PERSONID = 'MXSDFD'
) t;
rownum as seqnum
from t

Use PIVOT:
select personid,
"1_PHONEID" AS phoneid1,
"1_PHONENUM" AS phonenum1,
"1_TYPE" AS type1,
"1_ISPRIMARY" AS isprimary1,
"1_ROWSTAMP1" AS rowstamp1,
"2_PHONEID" AS phoneid2,
"2_PHONENUM" AS phonenum2,
"2_TYPE" AS type2,
"2_ISPRIMARY" AS isprimary2,
"2_ROWSTAMP1" AS rowstamp2,
"3_PHONEID" AS phoneid3,
"3_PHONENUM" AS phonenum3,
"3_TYPE" AS type3,
"3_ISPRIMARY" AS isprimary3,
"3_ROWSTAMP1" AS rowstamp3
from (
SELECT p.personid,
t.phoneid,
t.phonenum,
t.type,
t.isprimary,
t.rowstamp1,
ROW_NUMBER() OVER (
PARTITION BY p.personid ORDER BY t.isprimary DESC, t.rowstamp1 DESC
) AS seqnum
FROM person p
left join phone t
ON ( t.PERSONID = p.PERSONID )
where t.PERSONID = 'MXSDFD'
)
PIVOT (
MAX( phoneid ) AS phoneid,
MAX( phonenum ) AS phonenum,
MAX( type ) AS type,
MAX( isprimary ) AS isprimary,
MAX( rowstamp1 ) AS rowstamp1
FOR seqnum IN ( 1, 2, 3 )
)
Which, for the sample data:
CREATE TABLE person ( personid, name ) AS
SELECT 'MXSDFD', 'Alice' FROM DUAL;
CREATE TABLE phone ( personid, phonenum, phoneid, type, isprimary, rowstamp1 ) AS
SELECT 'MXSDFD', '012346', 1, 'A', 'N', TIMESTAMP '2020-10-13 09:00:00' FROM DUAL UNION ALL
SELECT 'MXSDFD', '555666', 3, 'C', 'N', TIMESTAMP '2020-10-13 08:30:00' FROM DUAL UNION ALL
SELECT 'MXSDFD', '987654', 2, 'B', 'Y', TIMESTAMP '2020-10-13 08:00:00' FROM DUAL;
Outputs:
PERSONID | PHONEID1 | PHONENUM1 | TYPE1 | ISPRIMARY1 | ROWSTAMP1 | PHONEID2 | PHONENUM2 | TYPE2 | ISPRIMARY2 | ROWSTAMP2 | PHONEID3 | PHONENUM3 | TYPE3 | ISPRIMARY3 | ROWSTAMP3
:------- | -------: | :-------- | :---- | :--------- | :--------------------------- | -------: | :-------- | :---- | :--------- | :--------------------------- | -------: | :-------- | :---- | :--------- | :---------------------------
MXSDFD | 2 | 987654 | B | Y | 13-OCT-20 08.00.00.000000000 | 1 | 012346 | A | N | 13-OCT-20 09.00.00.000000000 | 3 | 555666 | C | N | 13-OCT-20 08.30.00.000000000
db<>fiddle here

You seem to want logic like this:
select max(case when seqnum = 1 then t.PERSONID end) as PersonID,
max(case when seqnum = 1 then t.PHONEID end) as PhoneID1,
max(case when seqnum = 1 then t.PHONENUM end) as PhoneNum1,
max(case when seqnum = 1 then t.TYPE end) as Type1,
max(case when seqnum = 1 then t.ISPRIMARY end) as IsPrimary1,
max(case when seqnum = 1 then t.ROWSTAMP1 end) as Rowstamp1,
max(case when seqnum = 2 then t.PHONEID end) as PhoneID2,
max(case when seqnum = 2 then t.PHONENUM end) as PhoneNum2,
max(case when seqnum = 2 then t.TYPE end) as Type2,
max(case when seqnum = 2 then t.ISPRIMARY end) as IsPrimary2,
max(case when seqnum = 2 then t.ROWSTAMP1 end) as Rowstamp2,
max(case when seqnum = 3 then t.PHONEID end) as PhoneID3,
max(case when seqnum = 3 then t.PHONENUM end) as PhoneNum3,
max(case when seqnum = 3 then t.TYPE end) as Type3,
max(case when seqnum = 3 then t.ISPRIMARY end) as IsPrimary3,
max(case when seqnum = 3 then t.ROWSTAMP1 end) as Rowstamp3
from (select t.*, rownum as seqnum
from test1.phone t join
test2.person p
on t.PERSONID = p.PERSONID
where p.PERSONID = 'MXSDFD'
) t;
That said, you don't seem to need the join at all, because you are filtering on the join key (it is in both tables). So:
from (select t.*, rownum as seqnum
from test1.phone t
where t.PERSONID = 'MXSDFD'
) t

Related

Write a sql query to capture below information in a single row by using pivot

I have a table with three fields such as Name, Type and Amount
CREATE TABLE Customers
(
[Name] Varchar,
[Type] Varchar,
[Amount] int
);
INSERT INTO Customers (Name, Type, Amount)
VALUES ('Corporate', 'General', 300),
('Corporate', 'General', 400),
('Corporate', 'Specific', 4008);
And i want my output same like below
+-----------+---------+--------+---------+--------+----------+--------+
| Name | Type | Amount | Type | Amount | Type | Amount |
+-----------+---------+--------+---------+--------+----------+--------+
| Corporate | General | 300 | General | 400 | Specific | 4008 |
+-----------+---------+--------+---------+--------+----------+--------+
We might be able to use a ROW_NUMBER trick to pivot here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Amount) rn
FROM Customers
)
SELECT
Name,
MAX(CASE WHEN rn = 1 THEN Type END) AS Type1,
MAX(CASE WHEN rn = 1 THEN Amount END) AS Amount1,
MAX(CASE WHEN rn = 2 THEN Type END) AS Type2,
MAX(CASE WHEN rn = 2 THEN Amount END) AS Amount2,
MAX(CASE WHEN rn = 3 THEN Type END) AS Type3,
MAX(CASE WHEN rn = 3 THEN Amount END) AS Amount3
FROM cte
GROUP BY
Name;

sql inner join - multicolumn

can anyone help me with this sql query?
I have the following query:
select rps.res, rps.tar, rps.uni, rps.val
from TABLEX rps
where rps.res = '1'
or rps.res = '2'
or rps.res = '3'
order by rps.tar, rps.res asc
The Output looks like:
res | tar | uni | val
1 | A | B | 10
2 | A | B | 15
3 | A | B | 20
The output I would like to have is:
tar | uni | val1 | val2 | val3
Thanks in advance!
You can directly apply Conditional Aggregation :
select tar, uni,
max(case when tar = 1 then val end) as val1,
max(case when tar = 2 then val end) as val2,
max(case when tar = 3 then val end) as val3
from tab
group by tar, uni;
You can pivot using conditional aggregation and use row_number() for the numbering:
select tar, uni,
max(case when seqnum = 1 then val end) as val_1,
max(case when seqnum = 2 then val end) as val_2,
max(case when seqnum = 3 then val end) as val_3
from (select t.*,
row_number() over (partition by tar, uni order by val) as seqnum
from t
) t
group by tar, uni;

Spliting GROUP BY results into different columns

I have a column containing date ranges and the number of days passed associated to a specific ID (one to many), based on the number of records associated to it, I want those results split into columns instead of individual rows, so from this:
id_hr dd beg end
----------------------------------------
1 10 05/01/2019 15/01/2019
1 5 03/02/2019 08/02/2019
2 8 07/03/2019 15/03/2019
Could become this:
id_hr dd beg end dd beg end
--------------------------------- ---------------------
1 10 05/01/2019 15/01/2019 5 03/02/2019 08/02/2019
2 8 07/03/2019 15/03/2019
I did the same in a worksheet (pivot table) but the table became as slow as it could get, so I'm looking for a more friendly approach in SQL, I did a CTE which number the associated rows and then select each one and display them in new columns.
;WITH CTE AS(
SELECT PER_PRO, ID_HR, NOM_INC, rut_dv, dias_dur, INI, FIN,
ROW_NUMBER()OVER(PARTITION BY ID_HR ORDER BY SUBIDO) AS RN
FROM dbo.inf_vac WHERE PER_PRO = 201902
)
SELECT ID_HR, NOM_INC, rut_dv,
(case when rn = 1 then DIAS_DUR end) as DIAS_DUR1,
(case when rn = 1 then INI end) as INI1,
(case when rn = 1 then FIN end) as FIN1,
(case when rn = 2 then DIAS_DUR end) as DIAS_DUR2,
(case when rn = 2 then INI end) as INI2,
(case when rn = 2 then FIN end) as FIN2,
(case when rn = 3 then DIAS_DUR end) as DIAS_DUR3,
(case when rn = 3 then INI end) as INI3,
(case when rn = 3 then FIN end) as FIN3
FROM CTE
Which gets me each column on where it should be but not grouped. Using GROUP BY displays an error on the CTE select.
rn id_hr dd beg end dd beg end
----------------------------------- ------------------------
1 1 10 05/01/2019 15/01/2019 NULL NULL NULL
2 1 NULL NULL NULL 5 03/02/2019 08/02/2019
1 2 8 07/03/2019 15/03/2019 NULL NULL NULL
Is there any way to group them on the second select?
You have additional columns in the result set that are not in the query. However, this should work:
SELECT ID_HR,
max(case when rn = 1 then DIAS_DUR end) as DIAS_DUR1,
max(case when rn = 1 then INI end) as INI1,
max(case when rn = 1 then FIN end) as FIN1,
max(case when rn = 2 then DIAS_DUR end) as DIAS_DUR2,
max(case when rn = 2 then INI end) as INI2,
max(case when rn = 2 then FIN end) as FIN2,
max(case when rn = 3 then DIAS_DUR end) as DIAS_DUR3,
max(case when rn = 3 then INI end) as INI3,
max(case when rn = 3 then FIN end) as FIN3
FROM CTE
GROUP BY ID_HR;
Yes, you can GROUP BY all the non-CASE columns, and apply MAX to each of the CASE-expression columns.

SQL PIVOT table with MIN() and on Multiple columns

Here is the table structure
ID TypeX TypeXDesc XDate TypeCodeY
040001 3669 Unspecified Cat 2005-08-08 1
040001 3669 Unspecified Cat 2006-08-29 2
040001 37515 Tear Film 2005-08-08 1
040001 37999 Disor 2004-07-22 1
Transform above table INTO below USING PIVOT
ID TypeX_1 TypeXDesc_1 XDate_1 TypeCodeY_1 TypeX_2 TypeXDesc_2 XDate_2 TypeCodeY_2 TypeX_3 TypeXDesc_3 XDate_3 TypeCodeY_3
040001 3669 Unspecified Cat 2005-08-08 1 37515 Tear Film 2005-08-08 1 37999 Disor 2004-07-22 1
Look at the same TypeX code but XDate is different and we need to get Min(XDate) so first row is qualified not the second row.
You can accomplish this using conditional aggregation. In this case, you can enumerate the rows with within typex/id groups using row_number(). You can enumerate the groups with with typex/id using dense_rank().
Then, use conditional aggregation:
select t.id,
max(case when grpnum = 1 and seqnum = 1 then typex end) as typex_1,
max(case when grpnum = 1 and seqnum = 1 then TypeXDesc end) as TypeXDesc_1,
max(case when grpnum = 1 and seqnum = 1 then XDate end) as XDate_1,
max(case when grpnum = 1 and seqnum = 1 then TypeCodeY end) as TypeCodeY_1,
max(case when grpnum = 2 and seqnum = 1 then typex end) as typex_12,
max(case when grpnum = 2 and seqnum = 1 then TypeXDesc end) as TypeXDesc_2,
max(case when grpnum = 2 and seqnum = 1 then XDate end) as XDate_2,
max(case when grpnum = 2 and seqnum = 1 then TypeCodeY end) as TypeCodeY_3,
max(case when grpnum = 3 and seqnum = 1 then typex end) as typex_1,
max(case when grpnum = 3 and seqnum = 1 then TypeXDesc end) as TypeXDesc_3,
max(case when grpnum = 3 and seqnum = 1 then XDate end) as XDate_3,
max(case when grpnum = 3 and seqnum = 1 then TypeCodeY end) as TypeCodeY_3
from (select t.*,
row_number() over (partition by id, typex order by xdate as seqnum,
dense_rank() over (partition by id order by typex) as grpnum
from t
) t
group by id;

Aggregating a unique pair of column values from the same table based on a common column value

I have the following table:
my_table
------------------------
| common_id | uniq_val |
------------------------
| 1 | foo |
------------------------
| 1 | bar |
------------------------
And I want to aggregate values from it such that the resulting query looks like:
DESIRED RESULT
---------------------------------------
| common_id | uniq_val_1 | uniq_val_2 |
---------------------------------------
| 1 | foo | bar |
---------------------------------------
OR
---------------------------------------
| common_id | uniq_val_1 | uniq_val_2 |
---------------------------------------
| 1 | bar | foo |
---------------------------------------
So I've written the query:
SELECT t1.common_id, t1.uniq_val, t2.uniq_val
FROM my_table t1 JOIN my_table AS t2
ON t1.common_id=t2.common_id
WHERE t1.uniq_val!=t2.uniq_val;
Which results in
RESULTING SELECT
---------------------------------------
| common_id | uniq_val_1 | uniq_val_2 |
---------------------------------------
| 1 | foo | foo |
---------------------------------------
| 1 | bar | bar |
---------------------------------------
But I only need one of those columns, so I should be able to do a GROUP BY t1.common_id, like:
SELECT t1.common_id, t1.uniq_val, t2.uniq_val
FROM my_table t1 JOIN my_table AS t2
ON t1.common_id=t2.common_id
WHERE t1.uniq_val!=t2.uniq_val
GROUP BY t1.common_id;
Unfortunately this returns the error:
ERROR: column "t1.uniq_val" must appear in the GROUP BY clause or be used in an aggregate function
Can anyone point out the error in my logic?
How about simple aggregation?
select common_id, min(uniq_val) as uniq_val_1, max(uniq_val) as uniq_val_2
from my_table
group by common_id;
you can try distinct on
SELECT distinct on (t1.common_id) t1.common_id, t1.uniq_val, t2.uniq_val
FROM my_table t1 JOIN my_table AS t2
ON t1.common_id=t2.common_id
WHERE t1.uniq_val!=t2.uniq_val;
I think it will produce what you need!
This will handle up to 10 uniq_val values per common_id. You can remove or add to account for fewer or more uniq_val values if needed.
See a demonstration here with common_id values that have varying counts of uniq_val values:
http://sqlfiddle.com/#!15/e2c87/1/0
select common_id,
max(case when rn = 1 then uniq_val else null end) as uniq_val_1,
max(case when rn = 2 then uniq_val else null end) as uniq_val_2,
max(case when rn = 3 then uniq_val else null end) as uniq_val_3,
max(case when rn = 4 then uniq_val else null end) as uniq_val_4,
max(case when rn = 5 then uniq_val else null end) as uniq_val_5,
max(case when rn = 6 then uniq_val else null end) as uniq_val_6,
max(case when rn = 7 then uniq_val else null end) as uniq_val_7,
max(case when rn = 8 then uniq_val else null end) as uniq_val_8,
max(case when rn = 9 then uniq_val else null end) as uniq_val_9,
max(case when rn = 10 then uniq_val else null end) as uniq_val_10
from(
select row_number() over (partition by common_id order by common_id, uniq_val) as rn,
common_id,
uniq_val
from my_table
order by common_id, uniq_val) x
group by common_id
order by common_id