How to split select query rows based on the comma separated values in the columns in oracle plsql - sql

I wrote 2 queries Union. i'm getting results as comma separted in two of the columns. And the output is displayed as 2 records.
How to split them into 4 records as below expected results?
select emp_id,dept_name,location from department where dept_id = 1
union
select emp_id,dept_name,location from sales_dept where dept_id = 1;
Output:
emp_id ----- dept_name------ location
r1-----------Retail,IT----- US, UK
k2-----------Sales,Chemical- NZ, SA
j3-----------Biotech(Chemistry,Tech)- JA
I need the expected output as below:
emp_id ----- dept_name-----location
r1-----------Retail--------US
r1-----------IT----------- UK
k2-----------Sales---------NZ
k2-----------Chemical------SA
j3---------Biotech(Chemistry,Tech)--JA
The last record of whereever dept_name is "Biotech(Chemistry,Tech)" should be displayed as single record and not to be split. Please let me know how to do it.
The query given by Jim is working fine except in this scenario when dept_name is Biotech(Chemistry,Tech) as the requirement is given now.

Please use below query,
select emp_id, dept_name, location from
(select distinct emp_id, trim(regexp_substr(dept_name,'[^,]+', 1, level) ) dept_name,
trim(regexp_substr(location,'[^,]+', 1, level) ) location, level
from pivot_comma
connect by regexp_substr(dept_name, '[^,]+', 1, level) is not null
order by emp_id, level);

Related

How to group by in postgres by using MM-YYYY instead of DD_MM_YYYY?

I have created a query in PgAdmin, where one column named 'joining_date' in output returns a date.
When I use Group By I would like using only MM_YYY instead of DD_MM_YYY which is output datatype of 'joining_date' so that same employee_type can be grouped together.
create table employee(joining_date date,
employee_type varchar, name character varying);
insert into employee values
('16-11-2022', 'Intern', 'ABBS'),
('11-11-2022', 'senior', 'ABBS'),
('12-11-2022', 'senior', 'ABBS'),
('11-11-2022', 'senior', 'ABBS'),
('12-11-2022', 'Intern', 'ABBS');
select employee_type as emp,
to_char(joining_date, 'MM_YY') as batch,
count(employee_type) as num
from employee
GROUP BY employee_type, joining_date;
What I obtained is:
emp
batch
num
Intern
11_22
1
senior
11_22
1
Intern
11_22
1
senior
11_22
2
What I want to obtain is:
emp
batch
num
Intern
11_22
2
senior
11_22
3
How to proceed?
Your query is almost correct.
But you need to use the same formatting in selection and GROUP BY, otherwise your grouping has not the intended effect.
So if your selection should be done as TO_CHAR(joining_date, 'MM_YY'), this must be used in the GROUP BY clause, too.
SELECT employee_type AS emp,
TO_CHAR(joining_date, 'MM_YY') AS batch,
COUNT(employee_type) AS num
FROM employee
GROUP BY employee_type,
TO_CHAR(joining_date, 'MM_YY');
You can replicate here that this will produce the expected result: db<>fiddle

Oracle: union all query 1 and query 2 want to minus some rows if query 1 have rowdata

my query as below , i want to minus some rows from query1 when query2 have rowdata , but i don't know how to do:
my query:
with query1 as(
select wm_concat(linkman_name) name,
wm_concat(phone_num) phone,
t.org_id
from (
select linkman_name, phone_num, LINK_ORG_ID, org_id
from TD_SM_LINKMAN
where STATE = '2'
and (LINK_ORG_ID is null or LINK_ORG_ID = '')) t
group by t.org_id) ,
query2 as(
select wm_concat(linkman_name) name,
wm_concat(phone_num) phone,
org_id
from (select linkman_name, phone_num, LINK_ORG_ID, org_id
from TD_SM_LINKMAN
where STATE = '2'
and (LINK_ORG_ID = '55')) t
group by org_id)
select *
from query1
union all
select *
from query2 minus
-- this doesn't work ,i want to minus the rowdata from query 1 when query1.org_id = query2.org_id. the query2 is marked as outer query column.
(select * from query1 where query1.ORG_ID = query2.ORG_ID)
;
sample table
name phone link_org_id org_id
lily 133 1
ming 144 1
hao 333 2
jane 1234 55 2
bob 666 3
herry 555 3
query 1 result:
name phone org_id
lily,ming 133,144 1
hao 333 2
bob,herry 666,555 3
query 2 result:
name phone org_id
jane 1234 2
such like this , jane selected by query2 and hao selected by query 1 . All of them are from a same org which org_id =2 . but i don't need hao ,i just need jane. how to do?
i means if query2 can find result , then no need query1's result. but if query2 can't find any data, then i need query1's data.
The way it is now, you'll first have to split names (and phones) into rows, and then apply set operators (UNION, MINUS) to such a data.
Which means that you shouldn't use WM_CONCAT at all; at least, not at the beginning, because
first you concatenate data
then you'd have to split it back into rows
UNION / MINUS sets
Doing useless job in the first 2 steps.
I'd suggest you to UNION / MINUS data first, then aggregate them using WM_CONCAT. By the way, which database version do you use? WM_CONCAT is a) undocumented, b) doesn't even exist in latest Oracle database versions so you'd rather switch to LISTAGG, if possible.

How to get the first character of a row and group it with the first character of other rows and create a column from that

I would like to write an sql where in the table the first character of a row be grouped with different first letters of some rows and then that group is named.let's say that is a list of students. and I want students whose first name start with a particular letter to be put in a specific group. If there first name starts with A,B or C then they are put in a group and that group will be named 'Junior'; if their first name starts with D, E or F then they are put in a group that will be named 'Senior'. e.g.
KATE
JANE
MARY
NICOLE
ROBIN
A-C = Junior
D-F = Senior
G-I = Teacher
You don't need a group by clause, what you are asking is a simple DECODE or CASE expression.
Demo:
with data as
(
select 'ANGELINA' name from dual union all
select 'DAVID' from dual union all
select 'IAN' from dual union all
select 'NICOLE' from dual union all
select 'ROBIN' from dual
)
-- Your query starts here
select name,
case
when substr(name, 1, 1) in ('A','B','C')
then 'Junior'
when substr(name, 1, 1) in ('D','E','F')
then 'Senior'
when substr(name, 1, 1) in ('G','H','I')
then 'Teacher'
end as letter
from data;
NAME LETTER
-------- -------
ANGELINA Junior
DAVID Senior
IAN Teacher
NICOLE
ROBIN
The with data clause is only to build the sample data as you have not provided any. In your actual query, use your table name instead of data. Remove everything before the comment "-- Your query starts here".

how to get combine from Two select statements

my table is,
ID First_Name Last_name manager_ID Unique_ID
12 Jon Doe 25 CN=Jon Doe, DC=test,DC=COM
25 Steve Smith 39 CN=steve smith, DC=test,dc=com
I want to write a sql that will give me manager's unique ID,
select manager_id from test where ID = '12'
this will give me users manager_ID
select unique_id from test where ID = '25'
can i combine above sql in one statement that will give me user's manager's unique_id as output?
You are looking for a self-join:
select m.unique_id
from test t join
test m
on t.manager_id = m.id
where t.ID = 12;
Note that I remove the single quotes around 12. Presumably, id is an integer. You should not be comparing an integer to a string.
Instead of joining it to the same table, you can also make a nested subquery statement like this.
SELECT unique_id FROM test WHERE ID =(SELECT manager_id FROM test WHERE ID = 12);
The inner query outputs the manager_id where id of person equals 12 and the outer query gives the unique_id of the related manager.

Display a blank row between every unique row?

I have a simple query like:
SELECT employee, ITEM_TYPE, COUNT(ITEM_TYPE)
FROM hr_database
So the output may look like
BOB MUGS 4
BOB PENCILS 10
CAT MUGS 2
CAT PAPERCLIPS 7
SAL MUGS 11
But for readability, I want to put a blank row between each user in the output(i.e for readability), like this :
BOB MUGS 4
BOB PENCILS 10
CAT MUGS 2
CAT PAPERCLIPS 7
SAL MUGS 11
Is there a way to do this in Oracle SQL ? So far, I found this link but it doesn't match what I need . I'm thinking to use a WITH in the query?
You can do it in the database, but this type of processing should really be done at the application layer.
But, it is kind of an amusing trick to figure out how to do it in the database, and that is your specific question:
WITH e AS (
SELECT employee, ITEM_TYPE, COUNT(ITEM_TYPE) as cnt
FROM hr_database
GROUP BY employee, ITEM_TYPE
)
SELECT (case when cnt is not null then employee end) as employee,
item_type, cnt
FROM (select employee, item_type, cnt, 1 as x from e union all
select distinct employee, NULL, NULL, 2 as x from e
) e
ORDER BY e.employee, x;
I emphasize, though, that this is really for amusement and perhaps for understanding better how SQL works. In the real world, you do this type of work at the application layer.
A summary of how this works. The union all brings in one additional row for each employee. The x is a priority for sorting -- because you have to sort the result set to get the proper ordering. The case statement is needed to prevent the employee from being in the first column. cnt should never be NULL for the valid rows.
You can try like this with normal union & distinct
select emp,item_type,cnt from
(select distinct ' ' as emp,' ' as item_type ,' ' as cnt, employee
from hr_database
union
select employee as emp,item_type ,to_char(count(item_type)) as cnt, employee
from hr_database
group by employee,item_type)a
order by a.employee