How to joins in oracle based on condition - sql

I have two tables as below:
Table Apple:
+----------+----------+---------+
| APPLE_ID | PHONE_ID | IPAD_ID |
+----------+----------+---------+
| 1 | 1001 | 2001 |
| 2 | 1002 | 2002 |
| 3 | 1003 | 2003 |
| 4 | 1004 | 2004 |
+----------+----------+---------+
Table KEEY:
+---------+----------+--------+-----------+
| KEEY_ID | NAME | DTL_ID | DEVICE_ID |
+---------+----------+--------+-----------+
| 1 | PHONE_ID | 1001 | 111 |
| 2 | PHONE_ID | 2001 | 111 |
| 3 | IPAD_ID | 2001 | 222 |
| 4 | PHONE_ID | 1003 | 444 |
| 5 | MAC_ID | 367 | 333 |
+---------+----------+--------+-----------+
Desired Output:
+----------+----------+---------+-----------------+----------------+
| APPLE_ID | PHONE_ID | IPAD_ID | PHONE_DEVICE_ID | IPAD_DEVICE_ID |
+----------+----------+---------+-----------------+----------------+
| 1 | 1001 | 2001 | 111 | 222 |
| 3 | 1003 | 2003 | 444 | null |
+----------+----------+---------+-----------------+----------------+
Code Tried So far:
SELECT
APPLE.APPLE_ID,
APPLE.PHONE_ID,
APPLE.IPAD_ID,
NULL AS IPHONE_DEVICE_ID,
KY.DEVICE_ID AS IPAD_DEVICE_ID
FROM APPLE
LEFT JOIN KEEY KY ON APPLE.IPAD_ID=KY.DTL_ID WHERE KY.NAME='IPAD_ID'
UNION
SELECT
APPLE.APPLE_ID,
APPLE.PHONE_ID,
APPLE.IPAD_ID,
KY.DEVICE_ID AS PHONE_DEVICE_ID,
NULL AS IPAD_DEVICE_ID
FROM APPLE
LEFT JOIN KEEY KY ON APPLE.PHONE_ID=KY.DTL_ID WHERE KY.NAME='PHONE_ID'
This is giving me :
+----------+----------+---------+------------------+----------------+
| APPLE_ID | PHONE_ID | IPAD_ID | IPHONE_DEVICE_ID | IPAD_DEVICE_ID |
+----------+----------+---------+------------------+----------------+
| 1 | 1001 | 2001 | 111 | (null) |
| 1 | 1001 | 2001 | (null) | 222 |
| 3 | 1003 | 2003 | 444 | (null) |
+----------+----------+---------+------------------+----------------+
I guess i need to use pivot instead of Union to get both the ids on same row.
Have you ever encountered such scenarios? Any pointers to proceed will be very helpful.
Thanks in Advance!
DDL used for the above problem:
CREATE TABLE APPLE
( APPLE_ID INTEGER,
PHONE_ID INTEGER,
IPAD_ID INTEGER);
INSERT INTO APPLE VALUES (1,1001,2001);
INSERT INTO APPLE VALUES (2,1002,2002);
INSERT INTO APPLE VALUES (3,1003,2003);
INSERT INTO APPLE VALUES (4,1004,2004);
CREATE TABLE KEEY
( KEEY_ID INTEGER,
NAME VARCHAR2(50),
DTL_ID INTEGER,
DEVICE_ID INTEGER);
INSERT INTO KEEY VALUES (1,'PHONE_ID',1001,111);
INSERT INTO KEEY VALUES (2,'PHONE_ID',2001,111);
INSERT INTO KEEY VALUES (3,'IPAD_ID',2001,222);
INSERT INTO KEEY VALUES (4,'PHONE_ID',1003,444);
INSERT INTO KEEY VALUES (5,'MAC_ID',367,333);

I think you just want two joins:
select a.*, k1.device_id as phone_id, d2.device_id as ipad_id
from apple a join
keey k1
on a.phone_id = k1.dtl_id and k1.name = 'PHONE_ID' left join
keey k2
on a.ipad_id = k2.dtl_id and k2.name = 'IPAD_ID';
Here is a db<>fiddle (it uses Postgres just because that is easier to set up in the fiddle, but the results should be the same).

Another simple way to achieve the same would be UNION:
Select apple_id, phone_id, ipad_id, SUM(PHONE_DEVICE_ID), SUM(IPAD_DEVICE_ID)
from
(Select a.apple_id, a.phone_id, a.ipad_id ,
CASE WHEN k.NAME = 'PHONE_ID' THEN k.DEVICE_ID END PHONE_DEVICE_ID, 0 as IPAD_DEVICE_ID
from apple a
JOIN keey k ON a.phone_id = k.dtl_id AND k.name = 'PHONE_ID'
UNION ALL
Select b.apple_id, b.phone_id, b.ipad_id ,
0 as PHONE_DEVICE_ID, CASE WHEN j.NAME = 'IPAD_ID' THEN j.DEVICE_ID END IPAD_DEVICE_ID
from apple b
JOIN keey j ON b.IPAD_id = j.dtl_id AND j.name = 'IPAD_ID'
) group by apple_id, phone_id, ipad_id;
O/P:
+----------+----------+---------+-----------------+----------------+
| APPLE_ID | PHONE_ID | IPAD_ID | PHONE_DEVICE_ID | IPAD_DEVICE_ID |
+----------+----------+---------+-----------------+----------------+
| 1 | 1001 | 2001 | 111 | 222 |
+----------+----------+---------+-----------------+----------------+
| 3 | 1003 | 2003 | 444 | 0 |
+----------+----------+---------+-----------------+----------------+

Related

Replace nulls of a column with column value from another table

I have data flowing from two tables, table A and table B. I'm doing an inner join on a common column from both the tables and creating two more new columns based on different conditions. Below is a sample dataset:
Table A
| Id | StartDate |
|-----|------------|
| 119 | 01-01-2018 |
| 120 | 01-02-2019 |
| 121 | 03-05-2018 |
| 123 | 05-08-2021 |
TABLE B
| Id | CodeId | Code | RedemptionDate |
|-----|--------|------|----------------|
| 119 | 1 | abc | null |
| 119 | 2 | abc | null |
| 119 | 3 | def | null |
| 119 | 4 | def | 2/3/2019 |
| 120 | 5 | ghi | 04/7/2018 |
| 120 | 6 | ghi | 4/5/2018 |
| 121 | 7 | jkl | null |
| 121 | 8 | jkl | 4/4/2019 |
| 121 | 9 | mno | 3/18/2020 |
| 123 | 10 | pqr | null |
What I'm basically doing is joining the tables on column 'Id' when StartDate>2018 and create two new columns - 'unlock' by counting CodeId when RedemptionDate is null and 'Redeem' by counting CodeId when RedmeptionDate is not null. Below is the SQL query:
WITH cte1 AS (
SELECT a.id, COUNT(b.CodeId) AS 'Unlock'
FROM TableA AS a
JOIN TableB AS b ON a.Id=b.Id
WHERE YEAR(a.StartDate) >= 2018 AND b.RedemptionDate IS NULL
GROUP BY a.id
), cte2 AS (
SELECT a.id, COUNT(b.CodeId) AS 'Redeem'
FROM TableA AS a
JOIN TableB AS b ON a.Id=b.Id
WHERE YEAR(a.StartDate) >= 2018 AND b.RedemptionDate IS NOT NULL
GROUP BY a.id
)
SELECT cte1.Id, cte1.Unlocked, cte2.Redeemed
FROM cte1
FULL OUTER JOIN cte2 ON cte1.Id = cte2.Id
If I break down the output of this query, result from cte1 will look like below:
| Id | Unlock |
|-----|--------|
| 119 | 3 |
| 121 | 1 |
| 123 | 1 |
And from cte2 will look like below:
| Id | Redeem |
|-----|--------|
| 119 | 1 |
| 120 | 2 |
| 121 | 2 |
The last select query will produce the following result:
| Id | Unlock | Redeem |
|------|--------|--------|
| 119 | 3 | 1 |
| null | null | 2 |
| 121 | 1 | 2 |
| 123 | 1 | null |
How can I replace the null value from Id with values from 'b.Id'? If I try coalesce or a case statement, they create new columns. I don't want to create additional columns, rather replace the null values from the column values coming from another table.
My final output should like:
| Id | Unlock | Redeem |
|-----|--------|--------|
| 119 | 3 | 1 |
| 120 | null | 2 |
| 121 | 1 | 2 |
| 123 | 1 | null |
If I'm following correctly, you can use apply with aggregation:
select a.*, b.*
from a cross apply
(select count(RedemptionDate) as num_redeemed,
count(*) - count(RedemptionDate) as num_unlock
from b
where b.id = a.id
) b;
However, the answer to your question is to use coalesce(cte1.id, cte2.id) as id.

How to fill forward time series data in Postgres

I am looking to join three tables together and fill forward null values on the resulting table.
Three tables:
Table 1 (raw.fb_historical_data) - this is the main table on which I would like to join the other two on to. Each row of this table is related to one or more rows in the other two tables through a combination of columns id, clk and timestamp (mkt_id and row_id in the other tables).
+---------------------+-----+-----+--------------+
| timestamp | clk | id | some_columns |
+---------------------+-----+-----+--------------+
| 2016-06-19 06:11:13 | 123 | 126 | a |
| 2016-06-19 06:16:13 | 124 | 127 | b |
| 2016-06-19 06:21:13 | 234 | 126 | c |
| 2016-06-19 06:41:13 | 456 | 127 | d |
| ... | ... | ... | ... |
+---------------------+-----+-----+--------------+
Table 2 (raw.fb_runner_changes) - this table essentially gives price changes for a wide range of different markets
+---------------------+--------+--------+-------+
| timestamp | row_id | mkt_id | price |
+---------------------+--------+--------+-------+
| 2016-06-19 06:11:13 | 123 | 126 | 1 |
| 2016-06-19 06:21:13 | 123 | 126 | 2 |
| 2016-06-19 06:41:13 | 123 | 126 | 3 |
| 2016-06-06 18:54:06 | 124 | 127 | 1 |
| 2016-06-06 18:56:06 | 124 | 127 | 2 |
| 2016-06-06 18:57:06 | 124 | 127 | 3 |
| ... | ... | ... | ... |
+---------------------+--------+--------+-------+
Table 3 (raw.fb_runners) - a table with extra information about market changes that I would like to join
+---------------------+--------+--------+---------------+
| timestamp | row_id | mkt_id | other_columns |
+---------------------+--------+--------+---------------+
| 2016-06-19 06:15:13 | 234 | 126 | ab |
| 2016-06-19 06:31:13 | 234 | 126 | cd |
| 2016-06-19 06:56:13 | 234 | 126 | ef |
| 2016-06-06 18:54:06 | 456 | 127 | gh |
| 2016-06-06 18:56:06 | 456 | 127 | jk |
| 2016-06-06 18:57:06 | 456 | 127 | lm |
| ... | ... | ... | ... |
+---------------------+--------+--------+---------------+
Essentially what I want to do is fill NULL information forward (ordered by timestamp) while grouping by market id.
So far, I have tried to join the tables together using
SELECT *
FROM raw.fb_historical_data AS h
LEFT JOIN raw.fb_runner_changes AS rc
ON rc.row_id = h.clk
AND rc.timestamp = h.timestamp
AND rc.mkt_id = h.id
LEFT JOIN raw.fb_runners AS r
ON r.row_id = h.clk
AND r.timestamp = h.timestamp
AND r.mkt_id = h.id
Which has worked as intended, though now there are nulls in the resulting dataset which i'd like to fill in with the last available value for that market.
With some of the other SQL dialects, fill forward could be done using the window function last_value in combination with the instruction ignore nulls.
Since this is not supported in PostgreSQL (check the note at the bottom of this page), we are using a 2 steps work-around.
select ts, val, val_seq, min(val) over (partition by val_seq) val_fill_fw
from (select ts, val, count(val) over(order by ts) as val_seq
from t
) t
-
+----+----------+---------+-------------+
| ts | val | val_seq | val_fill_fw |
+----+----------+---------+-------------+
| 1 | (null) | 0 | (null) |
| 2 | (null) | 0 | (null) |
| 3 | hello | 1 | hello |
| 4 | (null) | 1 | hello |
| 5 | (null) | 1 | hello |
| 6 | darkness | 2 | darkness |
| 7 | my | 3 | my |
| 8 | (null) | 3 | my |
| 9 | old | 4 | old |
| 10 | (null) | 4 | old |
| 11 | (null) | 4 | old |
| 12 | (null) | 4 | old |
| 13 | friend | 5 | friend |
| 14 | (null) | 5 | friend |
+----+----------+---------+-------------+
SQL Fiddle
This seems to correctly do 'forward fill' in postgres. However I am a postgres newbie so I would appreciate feedback if it's wrong.
DROP TABLE IF EXISTS example;
create temporary table example(id int, str text, val integer);
insert into example values
(1, 'a', null),
(1, null, 1),
(2, 'b', 2),
(2,null ,null );
select * from example
select id, (case
when str is null
then lag(str,1) over (order by id)
else str
end) as str,
(case
when val is null
then lag(val,1) over (order by id)
else val
end) as val
from example

SQL MAX query using 3 tables

I'm having difficulty querying an SQL database.
| patient_id | episode_number | attend_practitioner | pract_assignment_date |
| ---------- | -------------- | ------------------- | --------------------- |
| 111 | 4 | 4444 | 01/05/2017 |
| 222 | 8 | 5555 | 03/17/2017 |
| 222 | 8 | 6666 | 03/20/2017 |
| 222 | 9 | 7777 | 04/10/2017 |
| 333 | 2 | 5555 | 10/08/2017 |
| 444 | 7 | 7777 | 08/09/2017 |
| patient_id | episode_number | backup_practitioner | date_of_assignment |
| ---------- | -------------- | ------------------- | ------------------ |
| 111 | 4 | | |
| 222 | 8 | 7777 | 03/17/2017 |
| 222 | 8 | 4444 | 05/18/2017 |
| 222 | 9 | | |
| 333 | 2 | 4444 | 10/08/2017 |
| 333 | 2 | 5555 | 10/19/2017 |
| patient_id | episode_number | admit_date |
| ---------- | -------------- | ---------- |
| 111 | 4 | 01/05/2017 |
| 222 | 8 | 03/17/2017 |
| 222 | 9 | 03/20/2017 |
| 333 | 2 | 10/08/2017 |
I'm looking for an SQL query where I can enter a staff_id and then have it return all the open episodes they are currently assigned to. Result:
| staff_id | patient_id | episode_number | admit_date | date_of_assignment |
| -------- | ---------- | -------------- | ---------- | ------------------ |
| 4444 | 111 | 4 | 01/05/2017 | 01/05/2017 |
| 4444 | 222 | 8 | 03/17/2017 | 05/18/2017 |
I don't understand how the SQL handles aliases in the query.
The SQL doesn't know what to do with SQL window functions such as OVER, LAG(), LEAD(), etc. So I'm using self joins along with the MAX() function. Maybe this is an older SAP SQL server.
I don't know whether capitalization in the SQL query is irrelevant.
This is a bit hard to work out from your question. I thin you need to most recent assignment for each patient/episode.
You could do this with a second sub-query using max, or you could use not exists as per below.
As you mentioned, it would be much easier with a row_number() and or CTE's, but this is bulk standard sql version.
select s.staff_id, e.patient_id, e.episode_number as episode_id, e.admit_date, s.date_of_assignment, c.last_date_of_service
from episode_history e
join (
select patient_id, episode_number, attend_practitioner as staff_id, pract_assignment_date as date_of_assignment
from history_attending_practitioner
union
select patient_id, episode_number, backup_practitioner as staff_id, date_of_assignment as date_of_assignment
from user_practitioner_assignment
where backup_practitioner is not null
) s on s.patient_id=e.patient_id and s.episode_number=e.episode_number
and not exists(select * from history_attending_practitioner a2 where a2.patient_id=s.patient_id and a2.episode_number=s.episode_number and a2.pract_assignment_date>s.date_of_assignment)
and not exists(select * from user_practitioner_assignment a3 where a3.patient_id=s.patient_id and a3.episode_number=s.episode_number and a3.date_of_assignment>s.date_of_assignment)
join view_episode_summary_current c on c.patient_id=e.patient_id and c.episode_number=e.episode_number
where e.discharge_date is null
After tweaking the query items, this is the SQL query version that returned the correct results:
SELECT
t1.staff_id
, t1.patient_id
, t3.admit_date
, t1.episode_number
, t1.date_of_assignment
FROM
/* select the most recent attending practitioner entry from table1 for the patient and episode */
(SELECT attending_practitioner AS staff_id, patient_id, episode_number, pract_assignment_date AS date_of_assignment
FROM table1 AS t1a
WHERE t1a.pract_assignment_date =
(SELECT MAX(pract_assignment_date)
FROM table1 AS t1b
WHERE t1b.patient_id = t1a.patient_id
AND t1b.episode_number = t1a.episode_number)
UNION
/* select the most recent practitioner entry from table2 for the patient and episode */
SELECT backup_practitioner AS staff_id, patient_id, episode_number, date_of_assignment
FROM table2 AS t2a
WHERE t2a.date_of_assignment =
(SELECT MAX(date_of_assignment)
FROM table2 AS t2b
WHERE t2b.patient_id = t2a.patient_id
AND t2b.episode_number = t2a.episode_number)
) AS t1
INNER JOIN
/* filter out closed episodes by using the table3 */
(SELECT patient_id AS patient_id2, episode_number AS episode_number2, admit_date
FROM table3) AS t3
ON t3.patient_id = t1.patient_id
AND t3.episode_number2 = t1.episode_number
WHERE t1.staff_id = '4444'

SQL Insert multiple value to one key staff from two tables (try to improve)

Basically, I want to insert multiple values to a signal staff form two tables, Value_table and Staff_table, which look like this:
Staff_table
| staff_num | staff_name | staff_role |
+---------------------+------------------+------------------+
| 1 | Bill | 1 |
| 2 | James | 1 |
| 3 | Gina | 2 |
| 4 | Tim | 3 |
Value_table
| value | value_name | value_state |
+------------------+------------------+------------------+
| 123 | Food | 0 |
| 476 | Drink | 1 |
| 656 | Dinner | 1 |
| 77 | Phone | 1 |
And the result should look like this:
| staff_num | value |
+---------------------+------------------+
| 1 | 123 |
| 1 | 476 |
| 1 | 656 |
| 1 | 77 |
| 2 | 123 |
| 2 | 476 |
| 2 | 656 |
| 2 | 77 |
.
.
.
.
I find a SQL way to do it which is the following code.
INSERT INTO Result_table
SELECT DISTINCT a.staff_code, c.func_num
FROM Staff_table a
JOIN Value_table c ON c.value BETWEEN 0 AND 656;
It works but I don't think the last line
JOIN Value_table c ON c.value BETWEEN 0 AND 656;
is a good way to select all the value from the table.
Is there a better way to do it in SQL?
Alternatively you may use CROSS JOIN as
INSERT INTO Result_table
SELECT distinct a.staff_code,c.func_num
FROM Staff_table a
CROSS JOIN Value_table c
Since, there's no need to restrict the value column which is already between 0 and 656 depending on the sample data.
Edit : If you want to restrict add a WHERE condition below as
INSERT INTO Result_table
SELECT distinct a.staff_code,c.func_num
FROM Staff_table a
CROSS JOIN Value_table c
WHERE c.value BETWEEN 77 and 123

How to remove duplicate values from oracle join?

I want to create a view that present only the results and not present the duplicates, I have 3 tables in oracle database:
The first table contain general information about a person
+-----------+-------+-------------+
| ID | Name | Birtday_date|
+-----------+-------+-------------+
| 1 | Byron | 12/10/1998 |
| 2 | Peter | 01/11/1973 |
| 4 | Jose | 05/02/2008 |
+-----------+-------+-------------+
The second table contain information about a telephone of the people in the first table.
+-------+----------+----------+----------+
| ID |ID_Person |CELL_TYPE | NUMBER |
+-------+- --------+----------+----------+
| 1221 | 1 | 3 | 099141021|
| 2221 | 1 | 2 | 099091925|
| 3222 | 1 | 1 | 098041013|
| 4321 | 2 | 1 | 088043153|
| 4561 | 2 | 2 | 090044313|
| 5678 | 4 | 1 | 092049013|
| 8990 | 4 | 2 | 098090233|
+----- -+----------+----------+----------+
The Third table contain information about a email of the people in the first table.
+------+----------+----------+---------------+
| ID |ID_Person |MAIL_TYPE | Email |
+------+- --------+----------+---------------+
| 221 | 1 | 1 |jdoe#aol.com |
| 222 | 1 | 2 |jdoe1#aol.com |
| 421 | 2 | 1 |xx12#yahoo.com |
| 451 | 2 | 2 |dsdsa#gmail.com|
| 578 | 4 | 1 |sasaw1#sdas.com|
| 899 | 4 | 2 |cvcvsd#wew.es |
+------+----------+----------+---------------+
if i do a inner join with this tables the result will do something like that
+-----+-------+-------------+----------+----------+----------+----------------+
| ID | Name | Birtday_date| CELL_TYPE| NUMBER |MAIL_TYPE|Email |
+-----+-------+-------------+----------+----------+----------+----------------+
| 1 | Byron | 12/10/1998 | 3 | 099141021|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 3 | 099141021|2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925|2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 1 | 098041013|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | 1 | 098041013|2 |jdoe1#aol.com |
| 2 | Peter | 01/11/1973 | 1 | 088043153|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | 1 | 088043153|2 |dsdsa#gmail.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313|2 |dsdsa#gmail.com |
| 4 | Jose | 05/02/2008 | 1 | 088043153|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | 1 | 088043153|2 |cvcvsd#wew.es |
| 4 | Jose | 05/02/2008 | 2 | 088043153|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | 2 | 088043153|2 |cvcvsd#wew.es |
+-----+-------+-------------+----------+----------+----------+----------------+
So the result that i will to present in a view is the next
+-----+-------+-------------+----------+----------+----------+----------------+
| ID | Name | Birtday_date| CELL_TYPE| NUMBER |MAIL_TYPE|Email |
+-----+-------+-------------+----------+----------+----------+----------------+
| 1 | Byron | 12/10/1998 | 3 | 099141021|1 |jdoe#aol.com |
| 1 | Byron | 12/10/1998 | | |2 |jdoe1#aol.com |
| 1 | Byron | 12/10/1998 | 2 | 099091925| | |
| 1 | Byron | 12/10/1998 | 1 | 098041013| | |
| 2 | Peter | 01/11/1973 | 1 | 088043153|1 |xx12#yahoo.com |
| 2 | Peter | 01/11/1973 | | |2 |dsdsa#gmail.com |
| 2 | Peter | 01/11/1973 | 2 | 090044313| | |
| 4 | Jose | 05/02/2008 | 1 | 092049013|1 |sasaw1#sdas.com |
| 4 | Jose | 05/02/2008 | | |2 |cvcvsd#wew.es |
| 4 | Jose | 05/02/2008 | 2 | 098090233| | |
+-----+-------+-------------+----------+----------+----------+----------------+
I tried to achieve a similar output using
case
when row_number() over (partition by table1.id order by table2.type) = 1
then table1.value
end
as "VALUE"
But the result is nothing that I expect and some rows they repeats
What you need to do is enumerate the rows and then join on those enumerations. This is tricky, because you don't know how many are in each list. Well, there is another method using conditional aggregation:
select p.id, p.name, p.birthday,
max(cell_type) as cell_type, max(number) as number,
max(mail_type) as mail_type, max(email) as email
from person p left join
((select id_person, cell_type, number,
null as mail_type, null as email,
row_number() over (partition by id_person order by number) as seqnum
from phones
) union all
(select id_person, null as cell_type, null as number,
mail_type, email,
row_number() over (partition by id_person order by email) as seqnum
from emails
)
) pe
on pe.id_person = p.id_person
group by p.id, p.name, p.birthday, pe.seqnum
Hope this helps.
Create table person(ID int ,Name varchar(20), Birtday_date date)
Insert into person values
(1,'Byron' ,'12/10/1998'),
(2,'Peter' ,'01/11/1973'),
(4,'Jose ' ,'05/02/2008')
Create table phones (ID int,ID_Person int,CELL_TYPE int,NUMBER float)
Insert into phones values
(1221, 1 , 3,099141021),
(2221, 1 , 2,099091925),
(3222, 1 , 1,098041013),
(4321, 2 , 1,088043153),
(4561, 2 , 2,090044313),
(5678, 4 , 1,092049013),
(8990, 4 , 2,098090233)
Create table emails(ID int,ID_Person int, MAIL_TYPE int, Email varchar(100))
Insert into emails values
(221, 1 , 1, 'jdoe#aol.com '),
(222, 1 , 2, 'jdoe1#aol.com '),
(421, 2 , 1, 'xx12#yahoo.com '),
(451, 2 , 2, 'dsdsa#gmail.com'),
(578, 4 , 1, 'sasaw1#sdas.com'),
(899, 4 , 2, 'cvcvsd#wew.es ')
select p.id, p.name, p.Birtday_date,
case when Lag(number) over(partition by p.id order by p.id,pe.id) = number then null else cell_type end as cell_type,
case when Lag(number) over(partition by p.id order by p.id,pe.id) = number then null else number end as number,
mail_type as mail_type, email as email
from person p left join
(select pp.ID_Person, cell_type, number, mail_type, email,pp.id from
(select ID_Person, cell_type, number,id,
row_number() over (partition by ID_Person order by id ) as seqnum
from phones
) pp left join
(select ID_Person,
mail_type, email, 1 as seqnum
from emails
)e on pp.ID_Person = e.ID_Person and pp.seqnum = e.seqnum
) pe
on pe.ID_Person = p.Id
order by p.id, pe.id