Select value based on priority of another column Oracle SQL - sql

I would like to select only one email address per id, if the id has both a work and personal email, I would only like to display the work email.
with emails as(
select '1' id, 'work' email_type, 'abc#gmail.com' email from dual union all
select '2' id, 'work' email_type, '123#yahoo.com' email from dual union all
select '2' id, 'personal' email_type, '456#msn.com' email from dual union all
select '3' id, 'personal' email_type, 'test#work.com' email from dual
)
For this example I would like to display:
id email_type email
1 work abc#gmail.com
2 work 123#yahoo.com
3 personal test#work.com

You can prioritize those values in row_number and get the first row for each id.
select id,email_type,email
from (select id,email_type,email
,row_number() over(partition by id order by case when email_type='work' then 1 else 2 end) as rn
from emails) t
where rn = 1

Assuming only possible value for email_type are work and personal, you can use window function row_number:
select *
from (
select t.*,
row_number() over (
partition by id order by email_type desc
) as seqnum
from emails t
) t
where seqnum = 1;

You can use a subquery to figure out if there is a work email or not. With your sample data, you can use the MAX function to return the "work" type if it exists, and if it doesn't it will just return "personal". Joining back on that will give the appropriate result.
WITH T1 AS (SELECT id, MAX(email_type) AS e_type FROM table_name GROUP BY id)
SELECT T1.id, T1.e_type, T2.email
FROM T1 LEFT JOIN table_name T2 ON T1.id = T2.id AND T1.e_type = T2.email_type
ORDER BY T1.id

Related

How to define unique value in union if two rows are not same data

I'm creating a simple SQL query with union, the result is returned correctly, but how to set a default value in a dummy column if the union result has two rows for one value?
If the result returned two values for one employee, then the dummy column is 'N' for the first value and 'Y' for the second value.
And if the result returned only one value for the employee, then the dummy column is 'Y'
How to achieve that?
This is the query that I'm using
select
dbo.employee,
dbo.starting_date
from
table_1
union
select
dbo.employee,
dbo.hiring_date
from
table_2
With a CTE:
with cte as (
select dbo.employee, dbo.starting_date date from table_1
union all
select dbo.employee, dbo.hiring_date date from table_2
)
select
t.*,
case when exists (
select 1 from cte
where employee = t.employee and date > t.date
) then 'N' else 'Y' end dummycolumn
from cte t
You can use window functions for this:
select t.employee, t.date,
(case when 1 = row_number() over (partition by t.employee order by t.date)
then 'Y' else 'N'
end) as dummy
from ((select t1.employee, t1.starting_date as date
from table_1 t1
) union all
(select t2.employee, t2.starting_date as date
from table_2 t2
)
) t

disply two rows from single row

This is the given table:
I need to get this data without creating temporary table based on the above table:
We can't use temporary table. I need to display the data with sql query only.
Try this
SELECT company name,'No' as value, clicks as data
from table1
union all
SELECT company,'Yes', (clicks - impression)
from table1
order by name,val
You can use UNION ALL to unpivot your table:
SELECT
company,
'No' AS val,
impression AS data
FROM tbl
UNION ALL
SELECT
company,
'Yes' AS val,
clicks - impression AS data
FROM tbl
ORDER BY company, val
You need UNION ALL
SELECT company,'No' val, impression as data from your_table
union all
SELECT company,'Yes' val, clicks-impression as data from your_table
select company as name, 'No' as val, impression as data
from tbl
union
select company as name, 'Yes' as val, clicks - impression as data
from tbl
SELECT COMPANY AS NAME, 'YES' AS VAL, (CLICKS-IMPRESSIONS) AS DATA
FROM ORIGINAL_TABLE
UNION
SELECT COMPANY AS NAME, 'NO' AS VAL, IMPRESSIONS AS DATA
FROM ORIGINAL_TABLE
If you want them sorted: Try this:
SELECT A.NAME, A.VAL, A.DATA FROM
(SELECT COMPANY AS NAME, 'YES' AS VAL, (CLICKS-IMPRESSIONS) AS DATA
FROM OR_TABLE
UNION
SELECT COMPANY AS NAME, 'NO' AS VAL, IMPRESSIONS AS DATA
FROM OR_TABLE) A
ORDER BY A.NAME ASC;

How can I filter an SQL table to show only keys with exactly N entries?

Lets say I have a table with a column named KEY.
I want to find all KEYs which are in the table exactly 3 times.
How can I do that?
I managed to get a list of how many entries I have for each KEY, like this:
select count(*) from my_table group by KEY;
but how can I filter it to show only those who have the value 3?
select KEY
from my_table
group by KEY
having count(*) = 3
The having clause filters after grouping (where filters before).
select `key`
from my_table
group by `KEY`
having count(*) = 3;
select KEY
from my_table
group by KEY
having count(1) = 3
Try with Row Number concept
;
WITH Temp_tab AS
( SELECT '1' Key_,'az' Key_Value
UNION SELECT '1' ,'a5'
UNION SELECT '1' ,'a6'
UNION SELECT '2' ,'a1'
UNION SELECT '3' ,'a2'
UNION SELECT '4' ,'a3'
UNION SELECT '1' ,'a4'
UNION SELECT '3' ,'a21'
UNION SELECT '3' ,'a22'),
Tab2 AS
(SELECT *, ROW_NUMBER() over(partition BY key_ ORDER BY key_) count_ FROM Temp_Tab)
SELECT key_
FROM tab2 WHERE count_ = 3
code for your table
;with temp_table
(select *,ROW_NUMBER() over(partition by key_ order by key_) count_ from my_table)
select key_ from temp_table where count_ = 3

SQL Union sort by Union

I have query
SELECT id, name
FROM users
WHERE id !=2
UNION
SELECT id, name
FROM users2
WHERE id != 3;
I want that sort will be, 1 union orders + 2 union it's possible ?
Add a column to order on
SELECT id, name, 1 as unionOrder FROM users WHERE id !=2
UNION
SELECT id, name, 2 as unionOrder FROM users2 WHERE id != 3
ORDER BY unionOrder
You can as well do like
(SELECT id, name
FROM users
WHERE id !=2
ORDER BY id)
UNION ALL
(SELECT id, name
FROM users2
WHERE id != 3
ORDER BY id);

ORDER BY CASE does not working?

Hi I have SQL statement in DB2 which is working.
select distinct 'IN' as STATUS,
(select count(*) from table.......)
from table
UNION ALL
select distinct 'OUT',
(select count(*) from table.......)
from table
UNION ALL
select distinct 'FINISHED',
(select count(*) from table.......)
from table
order by status
But if I change the last line to
order by
case STATUS
when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end
My query does not work.
Can someone tell me how to solve this?
Thanks
Try wrapping the UNION into a derived table and order on that:
select *
from (
.... here goes your statement ...
) t
order by
case STATUS
when 'IN' then 1
when 'OUT' then 2
when 'FINISHED' then 3
end
you could always add the sort # to the status:
select distinct '1-IN' as STATUS,
(select count(*) from table.......)
from table
UNION ALL
select distinct '2-OUT',
(select count(*) from table.......)
from table
UNION ALL
select distinct '3-FINISHED',
(select count(*) from table.......)
from table
order by status
hello try this should work if i remember correctly
order by
case
when STATUS='IN' then 1
when STATUS='OUT' then 2
when STATUS='FINISHED' then 3
end
you could also name this when finishing
end as field_name