sql foreach without using cursor - sql

I have a table "Student" in sql with a structure:
StudentId FirstName LastName
1 X Y
....
AND a table of Languages ,its structure:
LanguageId Name
1 English
2 Mandarin
3 Spanish
.....
and a relationship table StudentLanguage (languages spoken by a student)
StudentId LanguageId
1 1
1 3
2 1
2 2
from my asp.net page i want to filter students by spoken languages using checkboxes.
for example,when i check English,Madarin i want to have students speaking both English and Madarin
When i check French,Spanish ,English ==>Get students speaking French,AND English,AND Spanish.
to do that i pass a table of Languages paramter called #LanguageTable(LanguageId smallint) to a stored procedure.
how can i use this table to get the students without using a cursor.
I have tried with CTE but no result.

Try this:
select s.StudentId,s.FirstName,s.LastName
from Stundent s
join StudentLanguage sl on s.StudendID=sl.StudentId
join #LanguageTable on sl.LanguageId=#LanguageTable.LanguageId
group by s.StudentId,s.FirstName,s.LastName
having count(*)=(select count(*) from #LanguageTable)

You need relational division.
SELECT s.StudentId, s.FirstName, s.LastName
FROM Student s
WHERE NOT EXISTS(SELECT *
FROM #LanguageTable l
WHERE NOT EXISTS(SELECT *
FROM StudentLanguage sl
WHERE sl.LanguageId = l.LanguageId
AND sl.StudentId = s.StudentId))

I haven't tested this but:
SELECT s.StudentId, s.FirstName, s.LastName
FROM Student s
INNER JOIN StudentLanguage sl ON sl.StudentId = s.StudentId
INNER JOIN #Language l ON l.LanguageId = sl.LanguageId
GROUP BY s.StudentId, s.FirstName, s.LastName
HAVING Count(*) = (SELECT COUNT(*) FROM #Language)

Related

SQL Query conversion to Django ORM

select
l.student_id,
SUM(l.sum_result)
FROM
(
SELECT
w.student_id,
w.subject_id,
r.total as sum_result
from
Student w
INNER JOIN (
SELECT
COUNT(r.id) as total,
r.subject_fk_id
from
Result r
GROUP BY
r.subject_fk_id
) r ON w.subject_id = r.subject_fk_id
) l
GROUP BY
student_id
The tables are:
Student
-------------
-> id(PK)
->student_name
->student_email
Subject
--------------
-> id(PK)
-> subject_name
Results
---------------
->id (PK)
->subject_fk(FK to subject table)
->date
there is one many to many table for student and subject
Student_Subject
->id(PK)
->Student_id(FK)
->Subject_id(FK)
I want to convert this SQL query to Django ORM
I need to retreive the total number of results for a Student. I need to write this query in Django
ORM without for loops. Thank you in advance
your query missing a relationship part , also you can simplify your query to this :
select s.student_id,count(r.id)
from students s
Join student_subject ss
on ss.studentid = s.studentid
join subject sb
on sb.subject_id = ss.subject_id
join result r
on r.ssid = ss.id
group by s.student_id
so now I think you can write equivalent ORM yourself easily , right ? ;)

SQL Multiple Joins Query

Here I have two tables committee_colleges and colleges.
Structure of tables is something like this
committee_colleges
committeeCollegeId collegeId committeeMemberId
1 2 1
2 2 2
3 3 2
I am storing committeeMemberId from committeeMember table.And one college can have multiple committee Members.How can I wite a query to display only the colleges assigned to specific committee Member.
For Example,if committeeMember by id=2 has logged in I want to display colleges by id=2,3.
In college table I have like this,
collegeId typeName
1 AICTE
2 NCTE
3 NTCS
This is Committee Member table
committeeMemberId name
1 xyz
2 abc
Now I am writing something like this,but i know its wrong because I dont know how to take it from College table since I am displaying College details.
SELECT cc.committeeCollegeId as committeeCollegeId,
c.collegeId as collegeId,
cc.committeeMemberId as committeeMemberId
FROM committee_college as cc
left outer join College as c
on cc.collegeId = c.collegeId
where cc.committeeMemberId=:committeeMemberId
order by cc.committeeCollegeId asc
Can anyone tell how to display colleges based on its assignment to particular committeeMember?
You were close, you need INNER JOIN instead of LEFT JOIN:
SELECT DISTINCT C.typeName --<<== put here all the columns that you want in output
FROM committee_colleges CC
INNER JOIN college C
ON C.collegeId = CC.collegeId
WHERE CC.committeeMemberId = 2 --<<== your input parameter
EDIT: added DISTINCT
Hope it helps.
You can use below sql statement for the same
DECLARE #committeeMemberId INT = 2 -- Id of Committee member
;WITH CTE_MemberCommittee AS
(
SELECT CollegeId
FROM committee_colleges
WHERE committeeMemberId = #committeeMemberId
)
SELECT collegeId, typeName
FROM college
WHERE collegeId IN (SELECT CollegeId FROM CTE_MemberCommittee)
You can use simple inner join for that,
If you want collegename based on memberId use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.committeeMemberId = '2'
If you want collegename based on committemember name then use following query,
select a.collegeid,a.typeName from
college a, committee_colleges b, committe_member c
where a.collegeid = b.collegeid and
b.committeememberid = c.committeeMemberId
and c.Name = 'xyz'
Hope it will help.
try this:
DECLARE #LoginCommitteeMemberId INT=2
SELECT t2.Name AS MemberName,
t3.TypeName AS CollageName
FROM committee_college t1
INNER JOIN Committee_Member t2
ON t1.committeeMemberId = t2.committeeMemberId
INNER JOIN College as t3
ON t1.collegeId = t3.collegeId
WHERE t1.committeeMemberId = #LoginCommitteeMemberId

Complicated table join

I thought I had a good grasp on table joins but there is one problem here I can't figure out.
I am trying to track the progress of students on specifically required courses. Some students are required to complete an exact list of courses before further qualification.
Tables (simplified):
students
--------
id INT PRIMARY KEY
name VARCHAR(50)
student_courses
---------------
student_id INT PRIMARY KEY
course_id TINYINT PRIMARY KEY
course_status TINYINT (Not done, Started, Completed)
steps_done TINYINT
total_steps TINYINT
date_created DATETIME
date_modified DATETIME
courses
-------
id TINYINT PRIMARY KEY
name VARCHAR(50)
I want to insert a list of required courses, for example 5 different courses in the courses table and then select a specific student and get list of all the courses required, whether a row exists for that course in the student_courses table or not.
I guess I could insert all rows from the courses table in the student_courses table for each student, but I don't want that because not all students need to do these courses. And what if new courses are added later.
I just want a result which is something like this:
students table:
id name
--- ------------------
1 George Smith
2 Dana Jones
3 Maria Cobblestone
SELECT * FROM students (JOIN bla bla bla - this is the point where I'm lost...)
WHERE students.id = 1
Result:
id name course_id courses.name course_status steps_done
--- ------------------ --------- ------------ ------------- ----------
1 George Smith 1 Botany Not started 0
1 George Smith 2 Biology NULL NULL
1 George Smith 3 Physics NULL NULL
1 George Smith 4 Algebra Completed 34
1 George Smith 5 Sewing Started 2
If the course_status or steps_done is NULL it means that no row exists for this student for this course in the student_courses table.
The idea is then using this in MS Access (or some other system) and have the row automatically inserted in the student_courses table once you enter a value in the NULL field.
You can't just use an outer join to do this, you need to create a list of all students/classes combinations that you're interested in first, then use that list in a LEFT JOIN. Can be done in a cte/subquery using CROSS JOIN:
;WITH cte AS (SELECT DISTINCT s.id Student_ID
,s.name
,c.id Course_ID
,c.name Class_Name
FROM Students s
CROSS JOIN Courses c)
SELECT cte.*,sc.status
FROM cte
LEFT JOIN student_courses sc
ON cte.course_id = sc.course_id
Can also use a subquery if needs to be done in Access (not 100% on syntax in Access):
SELECT sub.*,sc.status
FROM (SELECT DISTINCT s.id Student_ID
,s.name
,c.id Course_ID
,c.name Class_Name
FROM Students s
CROSS JOIN Courses c
) AS sub
LEFT JOIN student_courses sc
ON sub.course_id = sc.course_id
Demo: SQL Fiddle
You want a left outer join. The first table is from the courses table and is used for the required courses (defined in the where clause).
select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
student_courses as sc
on sc.course_id = c.id and
sc.student_id = 1
) left join
students as s
on sc.student_id = s.id
where c.id in (<list of required courses>)
order by s.id, c.id;
I think I have all the "Access"isms in there.
Actually, the above will be missing the student name when s/he is missing a course. The following is more correct:
select s.id, s.name, c.id, c.name, c.course_status, c.steps_done
from (courses as c left join
student_courses as sc
on sc.course_id = c.id and
sc.student_id = 1
) cross join
students as s
on s.id = 1
where c.id in (<list of required courses>)
order by s.id, c.id;

SQL Query (or Join) for 3 tables

first time asking a question on Stack Overflow... Amazing resource, but there's just one thing that's really baffling me as a newcomer to SQL.
I have three tables and I would like to obtain the names of all the Mentors who are linked to Bob's students.
Table 1: TEACHERS
================
ID Name
================
1 Bob
Table 2: STUDENTS
===================================
STUDENT_ID Name TEACHER_ID
===================================
1 Jayne 1
2 Billy 5
3 Mark 2
Table 3: MENTOR_RELATIONSHIPS
==============================
ID STUDENT_ID MENTOR_ID
==============================
1 1 3
2 2 2
3 3 3
Table 4: MENTORS
=====================
MENTOR_ID Name
=====================
1 Sally
2 Gillian
3 Sean
I would like to run a query to find all of the mentors of Bob's students. So the mentors for all students with TEACHER_ID = 1
In this case Sean would be the result.
I know that it is something to do with Joins, or could I find this using a normal query??
Any help is much appreciated! Many thanks...
this should do the work
select distinct m.name from students s
inner join mentor_ralationships mr on mr.student_id=s.student_id
inner join mentors m on m.mentoir_id=mr.mentor_id
where s.teacher_id=1;
Without joins (not preferred)
SELECT mentors.name FROM mentors
WHERE mentors.id
IN (SELECT MENTOR_RELATIONSHIPS.mentor FROM MENTOR_RELATIONSHIPS
WHERE MENTOR_RELATIONSHIPS.student
IN (SELECT students.id FROM students WHERE students.teacher
= (SELECT teachers.id FROM teachers WHERE teachers.name = 'bob')));
It could be helpful for you as I had to retrieve data from three tables AssignedSubject, Section and SchoolClass when a teacher assigned to specific subject then I have to find out the his class and section details including subjectid which I did this way
select a.StaffID, a.SubjectID, s.ID as SectionId, s.Name as SectionName, S.Remarks as SectionRemarks, sc.ID as ClassId, sc.Name as ClassName, sc.Remarks as ClassRemarks from AssignedSubject a
inner join Section s on a.SectionId=s.ID
inner join SchoolClass sc on sc.ID=s.ClassId where a.StaffID=3068
You could try the following:
SELECT DISTINCT m.name
FROM students s INNER JOIN TEACHERS t ON t.ID = a.TEACHER_ID
INNER JOIN MENTOR_RELATIONSHIPS mr ON mr.Student_id = s.Student_id
INNER JOIN Mentors m ON mr.MENTOR_ID = s.MENTOR_ID
WHERE s.teacher_id = 1 WHERE t.Name = 'Bob';
SELECT TEACHER.NAME, STUDENTS.NAME AS STUDENT NAME, MENTORS.NAME AS MENTOR
FROM TEACHERS JOIN STUDENTS ON TEACHERS.ID = STUDENTS.TEACHER_ID
JOIN MENTOR_RELATIONSHIPS ON STUDENTS.STUDENT_ID =
MENTOR_RELATIONSHIPS.STUDENT_ID
JOIN MENTORS ON MENTOR_RELATIONSHIPS.MENTOR_ID = MENTORS.MENTOR_ID
WHERE TEACHER.NAME = 'Bob' ;

SQL issue,challenge

Say we have two entities:teacher and student.
each teacher has multiple student.
Now I want to:
query for at most 5 teachers,and for each teacher, no more than 10 of his student.
So far this can be done quite easily by:
select *,
(
select GROUP_CONCAT('<sid>',students.name,'</sid>') from students on
teachers.id=students.teacher limit 10
) as students
from teachers limit 5
But that's not the whole story yet.
AND
If anyone of the teachers has more than 10 students,should return true for that teacher,otherwise false
How to do this in SQL?
Pseudo SQL: one row of results for each of the 10 students for each of the 5 teachers
select t.teacher_id, s.student_id,
case when t2.count > 10 then 'true' else 'false' end
from
(select top 5 *
from teachers
order by teacher_id) t
join
(select top 10 *
from students s1 join teachers t1 on s1.teacher_id = t1.teacher_id
order by student_id) s
on t.teacher_id = s.teacher_id
join
(select teacher_id, count(*) as count
from teachers t join students s on t.teacher_id = s.teacher_id
group by teacher_id) t2
on t2.teacher_id = t.teacher_id
LINQ makes this super-easy
Use a subquery for every teacher selected.