Oracle Query to retrieve records when one of the conditions is true but not when both are true - sql

I have the following table and I want to retrieve students (STUD_ID) who have taken either ENGLISH or SCIENCE. If they have taken both ENGLISH and SCIENCE, then do not retrieve.
So the desired output is 101,102,104,106,107
The table is actually a View with the first 2 columns from the table STUD_INFO and the subject column are from a Nested table within the STUD_INFO table.
SELECT groupid,
Stud_id,
NST.Name
FROM STUD_INFO,
TABLE(SUBINFO) NST
Can anyone help me with a SQL query? The interesting part is when I use
Subject = ENGLISH and Subject = Science it does not retrieve any data.
groupid Stud_id Subject
------- ------- --------
1 101 ENGLISH
1 102 MATH
1 103 ENGLISH
1 103 SCIENCE
1 104 ENGLISH
1 104 MATH
1 105 PT
1 105 ENGLISH
1 105 SCIENCE
2 106 ENGLISH
2 107 SCIENCE
2 108 SCIENCE
2 108 ENGLISH

Subject = ENGLISH and Subject = SCIENCE says "Subject needs to be both ENGLISH and SCIENCE at the same time" which can never be true.
select stud_id from your_view
where subject in ('ENGLISH', 'SCIENCE')
group by stud_id
having count(subject) = 1
Does this work for you?

Related

how to pull all records in hive based on another column

If this is what my table looks like below:
my_id my_words my_people my_number
100 need more info? Jim 1
100 now Mary 2
100 what's that? Jim 3
101 okay now Jim 1
101 sounds good Mary 2
102 still hungry? Jim 1
102 now I'm thirsty though Mary 2
102 I don't understand Jim 3
102 no I'm not hungry Mary 4
103 are you there? Jim 1
103 I don't know Mary 2
103 That's okay Jim 3
How can I get this output?
my_id my_words my_people my_number
100 need more info? Jim 1
100 now Mary 2
100 what's that? Jim 3
102 still hungry? Jim 1
102 Now I'm thirsty though Mary 2
102 I don't understand Jim 3
right now I have: SELECT my_id, my_words, my_people, my_number from table where my_people="Mary" AND lower(my_words) like 'now%';
But I don't only want to return those rows, I also want to return Jim's comment right before and right after Mary's (before/after based on my_number column)
Maybe this is unrelated, but ultimately, I'm going to want this in Excel with this format:
my_id Jim_words Mary_words Jim_next_words
100 need more info? now what's that?
102 still hungry? now I'm thirsty though I don't understand
Could you please try below code? Code has explanations as comment.
WITH cte as (SELECT my_id, my_words, my_people, my_number
row_number() over( partition by my_id order by my_number) as rn --giving a unique row number for a my id
from table)
SELECT
distinct mytab.my_id, chosentab.my_words jims_words, mytab.my_people, mytab.my_number,
case when case when lower(mytab.my_words) like 'now%' then mytab.rn+1 end = chosentab.rn then chosentab.my_words end jims_words_after_marys_now,
case when case when lower(mytab.my_words) like 'now%' then mytab.rn-1 end = chosentab.rn then chosentab.my_words end jims_words_before_marys_now
FROM
cte mytab,
cte chosentab
where
mytab.my_id=chosentab.my_id and
case when lower(mytab.my_words) like 'now%' then mytab.rn+1 end = chosentab.rn and -- selecting jims rows where mary said now after jim
case when lower(mytab.my_words) like 'now%' then mytab.rn-1 end = chosentab.rn -- selecting jims rows where mary said now before jim
Now I created the SQL based on our discussion. Could you please validate and let me know it if worked?

Access SQL concatenating items by order

I have a need to concatenate name information from two tables in a specific order. So far, all I have is the SQL to retrieve the data. I need help with the SQL to output a name string in the correct order.
example data:
TBL_TITLE_ORDER
ORDER_ID
ORDER_SEQUENCE
TITLE_ID
FIRSTNAME_ID
20
1
30
20
2
456
20
3
33
21
1
31
21
2
32
TBL_TITLE
TITLE_ID
TITLE_NAME
30
Mr
31
Mrs
32
Jones
33
Smith
TBL_FIRSTNAME
FIRSTNAME_ID
NAME
456
John
SELECT TBL_TITLE.TITLE_NAME, TBL_FIRSTNAME.NAME
FROM (TBL_TITLE_ORDER LEFT JOIN TBL_TITLE ON TBL_TITLE_ORDER.TITLE_ID = TBL_TITLE.TITLE_ID) LEFT JOIN TBL_FIRSTNAME ON TBL_TITLE_ORDER.FIRSTNAME_ID = TBL_FIRSTNAME.FIRSTNAME_ID
WHERE (TBL_TITLE_ORDER.ORDER_ID) = 20
ORDER BY TBL_TITLE_ORDER.ORDER_SEQUENCE;
The output I need is a complete name string in the proper order sequence. There may or may not be a record in the TBL_FIRSTNAME table.
What I have so far:
TITLE_NAME
NAME
Mr
John
Smith
Required output:
Mr John Smith
Mrs Jones

Self JOIN to find the parent detail which matches with the row data -

I am trying to query in MS SQL and I can not resolve it. I have a table employees:
Id Name Surname FatherName MotherName WifeName Pincode isChild
-- ------- ------- ---------- ---------- -------- ------- -------
1 John Green James Sue null 101011 1
2 Michael Sloan Barry Lilly null 101011 1
3 Sally Green Andrew Molly Jemi 101011 1
4 Barry Sloan Soul Paul Lilly 101011 0
5 James Green Ned White Sue 101011 0
I want a query that selects rows where the father name and mother name of child matches with name and wife name. For the example table, where I want to return the result of rows where father and mother name matches the name and wife name column. For eg. id=1, where John's father name James and mother name Sue matches with id 5 which returns James as first name and Sue as wife name. So my query should return (this is my expected result)
Id Name Surname FatherName MotherName WifeName Pincode isChild
-- ------- ------- ---------- ---------- -------- ------- -------
5 James Green Ned White Sue 101011 0
4 Barry Sloan Soul Paul Lilly 101011 0
I tried with the below query but it checks for James only. How to change my query so that it checks all the names and returns the expected result.
select * FROM employees
where first_name like '%James%'
and wife_name like '%Sue%'
and pincode=101011;
Any tips on this will be really helpful. I am new to joins, need help on writing self join to get the result.
…
select *
from thetable as p -- the parent/father
where exists -- with one child at least
(
select *
from thetable as c
where c.fathername = p.name
and c.mothername = p.wifename
-- lastname?
)
Too long for a comment, but also not intended as a slam against what you are working with. Please take as constructive criticism.
Aside from VERY POOR DESIGN on the table content, getting that corrected before you get too deep into whatever you are working should be done first. A more typical design might be having a table of people. Now, to get the relationships you could do a couple ways. One is that on each individual person's record, you add 2 additional IDs. FatherID, MotherID. These IDs would join directly back to the child vs hard strings to match against. Take a surname like Smith or Jones. Then, look at the many instances of a "John Smith" may exist, yes a lot, and lower probability of finding a matching wife's name of Sue, Mary or whatever else name. But even that could lead to multiple possibilities. Yes, you are adding a PIN, but even a computer can generate a random pin of 1234.
By having the IDs, there is NO ambiguity of who the relationship is with.
If the data were slightly altered to something like
Id Name Surname FatherID MotherID SpouseID
-- ------- ------- ---------- ---------- --------
1 John Green 5 6 null
2 Michael Sloan 4 3 null
3 Lilly Sloan null null 4
4 Barry Sloan null null 3
5 James Green 9 10 6
6 Sue Green 7 8 5
7 Bill Jones null null 8
8 Martha Jones null null 7
9 Brian Green null null 10
10 Beth Smith-Green null null 9
So, in this modified example, you can see right away that ID#1 John Green has parents of Father (ID#5) is James and Mother (ID#6) is Sue. But even from this, James is a child to Father (ID#9) Brian and Mother (ID#10) Beth. This scenario is showing to a grand-parent level capacity and that each of James and Sue are also children but to their respective parents. Sue's parents of the Jones surname.
For Michael Sloan, parents of #4 Barry, and #3 Lilly.
And I additionally added a spouse ID. This prevents redundancy of people's names copied all over. Then you can query based on the child's parent's respective IDs to find out vs a hopeful name LIKE guess.
So, even though not solving a relatively simple query, fixing the underlying foundation of your database and is relations will, long-term, help ease your querying in the future.
Try this:
SELECT
T2.*
FROM Employee T1
JOIN Employee T2 ON T2.Name = T1.FatherName
AND T2.WifeName = T1.MotherName

Avoid Null values in Coalesce

I have used coalesce to produce results but got duplicate rows with Null values.
Sample tables as below:
Table - Student
ID Student Subject id Subject Grade id
100 Peter 200 Chinese 201
101 Mary 300 English 302
102 Sam 400 Maths 403
103 John 900 Music
Chinese Table
Subject id Grade id Grade
200 201 Good
200 202 Average
200 203 Poor
English Table
Subject id Grade id Grade
300 301 Good
300 302 Average
300 303 Poor
Maths Table
Subject id Grade id Grade
400 401 Good
400 402 Average
400 403 Poor
Select Id, Name,
Coalesce (chinese.grade, english.grade, maths.grade)
from Student
Left join Chinese On student.id = Chinese.subjectId AND student.gradeId = Chinese.gradeId
Left join English On student.id = English.subjectId AND student.gradeId = Enlgish.gradeId
Left join Maths On student.id = Maths.subjectId AND student.gradeId = Maths.gradeId
Result
ID Student Subject Grade
100 Peter Chinese Good
100 Peter Chinese NULL
101 Mary English Average
101 Mary English NULL
102 Sam Maths Poor
102 Sam Maths NULL
103 John Music NULL
I am not sure where the duplicated row of Null values came from, just want to know how can I avoid giving null values by using coalesce?
Answering the "just want to know how can I avoid giving null values by using coalesce?" part of the question only, since the origin of the duplicate records requires more information than was provided:
COALESCE returns the first non-null value in its argument list, or NULL if all arguments are NULL.
So Select Id, Name, Coalesce (chinesetable.grade, englishtable.grade, mathstable.grade) ... will still give you a NULL grade if all of chinesetable.grade, englishtable.grade, and mathstable.grade are NULL. You need to decide what you want to do in that situation. You could either skip those rows:
Select * From
(Select Id, Name, Coalesce (chinesetable.grade, englishtable.grade, mathstable.grade) As Grade from Student where id = id...) As grades_with_nulls
Where Grade Is Not Null;
Or provide a default value as the last argument to Coalesce:
Select Id, Name, Coalesce (chinesetable.grade, englishtable.grade, mathstable.grade, 'None') from Student where id = id...
Use:
select s.id,s.name,s.[subject],
coalesce(coalesce(coalesce(c.grade,e.grade,c.grade),e.grade, coalesce(c.grade,e.grade,c.grade)),m.grade,coalesce(coalesce(c.grade,e.grade,c.grade),e.grade, coalesce(c.grade,e.grade,c.grade))) as grade
from student s
left join chinese c on s.subjectid = c.subjectid and c.gradeid = s.gradeid
left join english e on e.subjectid = s.subjectid and e.gradeid = s.gradeid
left join maths m on m.subjectid = s.subjectid and m.gradeid = s.gradeid
result
id--name----subject--grade
100 Peter Chinese Good
101 Mary English Average
102 Sam Maths Poor
103 John Music NULL

How to get the student academic progress?

course Table
course_code course_name credit_points_reqd
1 Comp Science 300
2 Soft Engineering 300
subject Table
subject_code subject_name credit_points
CS123 C Prog 15
CS124 COBOL 15
enrolment table
student_id student_name course_code subject_code Results
1 Lara Croft 1 CS123 70
1 Lara Croft 1 CS124 50
2 Tom Raider 2 CS123 60
2 Tom Raider 2 CS124 40
3 James Bond 1 CS123 NULL
3 James Bond 1 CS124 40
OUTPUT TABLE
student_name course_name credit_points_obt credit_points_reqd
Lara Croft Comp Science 30 300
Tom Raider Soft Engineering 15 300
I'm currently using TSQL. So here's the situation. I've prepared these tables to get the output like the way it i showed u up there. I need to calculate the credit points obtained. Credit points are achieved if the student receives > 50 for a subject they took. I want to ignore students that has not received any credit points at all (eg, James Bond is ignored as he has not achieved any points yet)
select student_name, course_name,credit_points_obt,credit_points_reqd
FROM enrolment (SELECT student_full_name, SUM(credit_points) AS credit_points_obt
FROM enrolment
GROUP BY student_id),
Totally stuck...I have no idea where to go now.
You can sum conditionally to get points for subject. If none are given result will be null, so you filter out those student/course pairs in having clause.
I've changed > 50 condition to >= 50 because your results contradict your requirements. Also, by the data I'd say that you have omitted student table for brewity, but if you haven't, it is a must.
Live test is # Sql Fiddle.
select enrolment.student_name,
course.course_name,
course.credit_points_reqd,
sum(case when enrolment.results >= 50
then subject.credit_points
end) credit_points_obt
FROM enrolment
inner join course
on enrolment.course_code = course.course_code
inner join subject
on enrolment.subject_code = subject.subject_code
group by enrolment.student_name,
course.course_name,
course.credit_points_reqd
having sum(case when enrolment.results >= 50
then subject.credit_points
end) is not null