obiee query to find out multiple races in a column in one - sql

SET VARIABLE PREFERRED_CURRENCY='User Preferred Currency 1';SELECT
0 s_0,
"People - People Real Time"."People Details"."People Full Name" FullName,
case
when "People - People Real Time"."Job Application - Legislative Information"."Ethnicity" like '%,%' then 'Two Or More Races'
else "People - People Real Time"."Job Application - Legislative Information"."Ethnicity" end as Ethnicity,
"People - People Real Time"."Job Application - Legislative Information"."Gender" Gender,
"People - People Real Time"."Job Requisition - Basic Information"."Requisition Number" RequisitionNumber
FROM "People - People Real Time"
where "People - People Real Time"."Job Requisition - Basic Information"."Requisition Number" = :reqNumber
ORDER BY "People - People Real Time"."Job Application - Job Application Dates"."Creation Date" desc, 1, 2 ASC NULLS LAST, 3 ASC NULLS LAST, 4 ASC NULLS LAST, 5 ASC NULLS LAST
I am getting the output like -
FullName Ethnicity Gender RequisitionNumber
Smith Hispanic M 10
Smith Englush M 10
Smith Hindi M 10
Test English F 11
I want the above query to be tweaked in a way that i get the output as
FullName Ethnicity Gender RequisitionNumber
Smith Two Or More Races M 10
Test English F 11
I cannot use many functions in the query ( i can use Count) because it is OBIEE

Continuing on the output you got already...
WITH
dataset AS
(
Select 'Smith' "FULL_NAME", 'Hispanic' "ETHNICITY", 'M' "GENDER", 10 "REQUISITION_NUMBER" From Dual Union All
Select 'Smith' "FULL_NAME", 'English' "ETHNICITY", 'M' "GENDER", 10 "REQUISITION_NUMBER" From Dual Union All
Select 'Smith' "FULL_NAME", 'Hindi' "ETHNICITY", 'M' "GENDER", 10 "REQUISITION_NUMBER" From Dual Union All
Select 'Test' "FULL_NAME", 'English' "ETHNICITY", 'F' "GENDER", 11 "REQUISITION_NUMBER" From Dual
)
SELECT DISTINCT
FULL_NAME,
CASE WHEN Count(*) OVER(PARTITION BY FULL_NAME, GENDER, REQUISITION_NUMBER) > 1 THEN 'Two Or More Races' ELSE ETHNICITY END "ETHNICITY",
GENDER,
REQUISITION_NUMBER
FROM
dataset
/* R e s u l t :
FULL_NAME ETHNICITY GENDER REQUISITION_NUMBER
--------- ----------------- ------ ------------------
Test English F 11
Smith Two Or More Races M 10
*/
One of the options is to use CASE expresion with Count() analytic function to transform the ETHNICITY column to the text you want. There are multiple rows initialy so the DISTINCT keyword is used to get your expected result.
Regards...

Related

SQL query to check if a value isn't present

First of all, I really don't know how to formulate my question.
I have different companies in a database.
I would like to know which companies doesn't have an "analyst" profile.
Here is my query:
select
t.name as "name"
t.pre as "first name"
t.id as "# account"
t.profile as "Profile"
b.cod_miss as "Mission"
b.df_missn as "End date"
from sr.v t
inner join od.e_lds on t.niu_ld = b.niu_ld
where b.cod_miss = 'APPROV'
and t.profile = 'Analyst'
This query gives me all the analyst for every companies in my database.
But I would like to have all the companies that does NOT have any analyst.
how do I do it? I tried using 'and t.profile <> 'analyst' " but obviously this is not working well...
EDIT:
I tried the accepted answer, but i noticed it just returns me everyone that is NOT an analyst.
Let's say there is a company X with 3 employees. One of them is an analyst. I would not want that company to come up in my results. but if there is company Y with 2 employees, and none of them is an "analyst", then I would like this company to come up in the result.
If I understood you correctly, that would be not exists. Something like this:
select *
from sr.v
where not exists (select null
from od.e_lds b
where b.niu_ld = t.niu_ld
and t.profile = 'Analyst'
);
Applied to your query:
select
t.name as "name"
t.pre as "first name"
t.id as "# account"
t.profile as "Profile"
b.cod_miss as "Mission"
b.df_missn as "End date"
from sr.v t inner join od.e_lds b on t.niu_ld = b.niu_ld
where b.cod_miss = 'APPROV'
--
and not exists (select null
from od.e_lds c
where c.niu_ld = t.niu_ld
and t.profile = 'Analyst'
);
[EDIT #2, with some sample data]
This is an example that shows what you tried to explain in words (would be better if you posted sample data, though). As you can see, one of employees in BMW is Analyst while nobody in SAP is >> therefore, SAP is being returned.
SQL> with test (company, ename, profile) as
2 (select 'BMW', 'Scott', 'Analyst' from dual union all
3 select 'BMW', 'King' , 'Manager' from dual union all
4 select 'BMW', 'Mike' , 'Clerk' from dual union all
5 --
6 select 'SAP', 'John' , 'Clerk' from dual union all
7 select 'SAP', 'Fred' , 'Manager' from dual
8 )
9 select a.company, a.ename, a.profile
10 from test a
11 where not exists (select null
12 from test b
13 where b.company = a.company
14 and b.profile = 'Analyst');
COMPANY ENAME PROFILE
---------- ----- -------
SAP Fred Manager
SAP John Clerk
SQL>

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".

SQL Query that summarizes students marks in a report card

Stupid simple question that I ended up spending 3.5 hours on. I'm running into a lot of syntax errors, so if anyone could help me answer this, I would learn a lot! Thank you so much!
I have 3 database tables:
Students Table
student_id, name
1, joe
2, jill
Courses Table
course_id, course_name
eng123, Engineering
stat111, Statistics
Marks Table
student_id, course_id, mark
1, stat111, 64
2, stat111, 90
1, eng123, 86
I need to write a single SQL query that will give me a summed up report card that looks like this:
student_id, student_name, eng123, stat 111
1, joe, 86, 64
2, jill, null, 90
---WHAT I EXPLORED:
I have looked into PIVOT, CASE and GROUP BY as my main leads, but I cannot put together the final pieces. My most promising query so far has been:
SELECT Students.student_id, Students.student_name,
CASE course_id WHEN 'eng123' THEN mark END as 'eng123',
CASE course_id WHEN 'stat111' THEN mark END as 'stat111'
FROM Students
INNER JOIN Marks
ON Students.student_id=Marks.student_id;
But that gives me the incorrect results of:
student_id, student_name, eng123, stat111
1, joe, null, 64
1, joe, 86, null
2, jill, null, 90
Your promising query is a stone's throw away from being what you want. You can simply modify it to GROUP BY the student_id and student_name (which should always pair the same together). Then take the sum of the marks. Note that I have added ELSE conditions to your CASE statements which assign a value of 0 (which therefore won't affect the sum aggregate).
SELECT Students.student_id, Students.student_name,
SUM(CASE course_id WHEN 'eng123' THEN mark ELSE 0 END) as 'eng123',
SUM(CASE course_id WHEN 'stat111' THEN mark ELSE 0 END) as 'stat111'
FROM Students
INNER JOIN Marks ON Students.student_id=Marks.student_id
GROUP BY Students.student_id, Students.student_name
Hi try using aggregate function MAX. try this:
WITH x AS (SELECT 1 AS student_id, 'joe' AS student_NAME FROM dual UNION ALL
SELECT 2 AS student_id, 'jill' AS student_NAME FROM dual),
y AS (SELECT 1 AS student_id , 'stat111' AS course_id, 64 AS mark FROM dual UNION ALL
SELECT 2 AS student_id , 'stat111' AS course_id, 90 AS mark FROM dual UNION ALL
SELECT 1 AS student_id , 'eng123' AS course_id, 86 AS mark FROM dual )
SELECT x.student_id, x.student_name,
MAX (CASE WHEN course_id = 'eng123' THEN mark END) eng123,
max(CASE WHEN course_id = 'stat111' THEN mark END) stat111
FROM x
INNER JOIN y
ON x.student_id=y.student_id
group by x.student_id, x.student_name;
select student_id,student_name,
max(case when course_id = 'eng123' then mark end) as eng123,
max(case when course_id = 'stat111' then mark end) as stat111
from (
SELECT Students.student_id as student_id,
Students.name as student_name,
Marks.course_id as course_id,
Marks.mark as mark
FROM Student Students
INNER JOIN Marks
ON Students.student_id=Marks.student_id)Z
group by student_id,student_name

SQL - Query using Join / Having / Subquery - How

Please suggest a sql query to fetch the
"list of students and corresponding subject in which student has same score , if the student has same score in more than one subject"
eg.
Student Subject Score
John Science 80
John Maths 80
John English 80
John French 80
Peter Science 85
Peter Maths 70
Peter English 70
Peter French 70
Mathews French 70
Expected Result :
John Science
John Maths
John English
John French
Peter Maths
Peter English
Peter French
tried -
select person , subject where person in
( select person , score , count(score) group by person , score having count(score) > 1 )
but in this "Peter Science" appears , which is not required.
Please assist.
Thanks
Try:
select person , subject
from table t
join
( select person , score , count(score)
from table
group by person , score having count(score) > 1
) foo
on t.person = foo.person
where t.person = foo.person
and t.score = foo.score
The reason your query didn't work (aside from not including a table):
Your inner query was selecting the students and scores that match your criteria. But your outer query was selecting everything for all students who matched the criteria, which is why "peter science" was being included. So, you needed to limit the results in your outer query to only those that match all of your criteria.
You should tell us what RDBMS are you using. But this should work everywhere:
select
t.*
from <tableName> t
join (
select
student, score
from <tableName>
group by
student, score
having count(*)>1
) x
on t.student=x.student
and t.score=x.score
Btw you're missing FROM <tableName> in your query.
Try with this :
select student, subject
from Person
where student + cast(score as varchar(20)) in
(
select student + cast(score as varchar(20)) from Person group by student,score having count(score) > 1
)
You can achieve this goal self-joining table like in example:
SELECT
t.Student,
t.Subject,
t.Score
FROM Table1 AS t
JOIN
(
SELECT Student, Score FROM Table1 GROUP BY Student, Score HAVING COUNT(*) > 1
) AS t1 ON t.Student = t1.Student AND t.Score = t1.Score
Full example with test data and created table you can find here:
http://sqlfiddle.com/#!2/61f02/8

Collapse Multiple Records Into a Single Record With Multiple Columns

In a program I'm maintaining we were given a massive (~500 lines) SQL statement by the customer. It is used for generating flat files with fixed length records for transmitting data to another big business. Since its a massive flat file its not relational and the standard normal forms of data are collapsed. So, if you have a record that can have multiple codes associated, in this case upto 19, they all have be written into single line, but seperate fields, in the flat file.
Note: this example is simplified.
The data might look like this, with three tables:
RECORDS
record_id firstname lastname
--------------------------------
123 Bob Schmidt
324 George Washington
325 Ronald Reagan
290 George Clooney
CODE_TABLE
code_id code_cd code_txt
--------------------------------
5 3 President
2 4 Actor
3 7 Plumber
CODES_FOR_RECORDS
record_id code_cd
-------------------
123 7
325 3
290 4
324 3
325 4
123 4
This needs to produce records like:
firstname lastname code1 code2 code3
Bob Schmidt Actor Plumber NULL
George Washington President NULL NULL
Ronald Reagon Actor President NULL
George Clooney Actor NULL NULL
The portion of the current query we were given looks like this, but with 19 code columns instead of the 5:
select
x.record_id,
max(case when x.rankk = 1 then code_txt end) as CodeColumn1,
max(case when x.rankk = 2 then code_txt end) as CodeColumn2,
max(case when x.rankk = 3 then code_txt end) as CodeColumn3,
max(case when x.rankk = 4 then code_txt end) as CodeColumn4,
max(case when x.rankk = 5 then code_txt end) as CodeColumn5,
from
(
select
r.record_id,
ct.code_txt as ctag ,
dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk
from
records as r
codes_for_records as cfr,
code_table as ct
where
r.record_id = cfr.record_id
and ct.code_cd = cfr.code_cd
and cfr.code_cd is not null
and ct.code_txt not like '%V%'
) as x
where
x.record_id is not null
group by
x.record_id
I trimmed down things for simplicties sake, but the actual statment includes an inner query and a join and more where conditions, but that should get the idea across. My brain is telling me there has to be a better way, but I'm not an SQL expert. We are using DB2 v8 if that helps. And the codes have to be in seperate columns, so no coalescing things into a single string. Is there a cleaner solution than this?
Update:
I ended up just refacorting the original query, it sill uses the ugly MAX() business, but overall the query is much more readable due to reworking other parts.
It sounds like what you are looking for is pivoting.
WITH joined_table(firstname, lastname, code_txt, rankk) AS
(
SELECT
r.firstname,
r.lastname,
ct.code_txt,
dense_rank() over (partition by r.record_id order by cfr.code_id) as rankk
FROM
records r
INNER JOIN
codes_for_records cfr
ON r.record_id = cfr.record_id
INNER JOIN
codes_table ct
ON ct.code_cd = cfr.code_cd
),
decoded_table(firstname, lastname,
CodeColumn1, CodeColumn2, CodeColumn3, CodeColumn4, CodeColumn5) AS
(
SELECT
firstname,
lastname,
DECODE(rankk, 1, code_txt),
DECODE(rankk, 2, code_txt),
DECODE(rankk, 3, code_txt),
DECODE(rankk, 4, code_txt),
DECODE(rankk, 5, code_txt)
FROM
joined_table jt
)
SELECT
firstname,
lastname,
MAX(CodeColumn1),
MAX(CodeColumn2),
MAX(CodeColumn3),
MAX(CodeColumn4),
MAX(CodeColumn5)
FROM
decoded_table dt
GROUP BY
firstname,
lastname;
Note that I've never actually done this myself before. I'm relying on the linked document as a reference.
You might need to include the record_id to account for duplicate names.
Edit: Added the GROUP BY.
One of the possible solutions is using of recursive query:
with recursive_view (record_id, rankk, final) as
(
select
record_id,
rankk,
cast (ctag as varchar (100))
from inner_query t1
union all
select
t1.record_id,
t1.rankk,
/* all formatting here */
cast (t2.final || ',' || t1.ctag as varchar (100))
from
inner_query t1,
recursive_view t2
where
t2.rankk < t1.rankk
and t1.record_id = t2.record_id
and locate(t1.ctag, t2.final) = 0
)
select record_id, final from recursive_view;
Can't guarantee that it works, but hope it will be helpful. Another way is using of custom aggregate function.