Querying an Odoo many-to-many field using raw SQL - sql

I want to display many-to-many field in report.
Currently my model is as follows:
from openerp.esv import orm, fields
class myClass(orm.Model):
_name = 'my.Class'
_columns = {
'teacher_id': fields.many2many('fci.staff','lgna_teacher','ids_lol',
'teacher_ids','Observers'),
}
And I want to display them using SQL select statement.

In my example below, I'm considering that teachers and courses have a many-to-many relationship: teachers can teach multiple courses and courses can be taught by multiple teachers.
from openerp.osv import orm, fields
class Teachers(orm.Model):
_name = 'teachers'
name = fields.Char()
class Course(rm.Model):
_name = 'course'
title = fields.Char()
teacher_ids = fields.Many2many('teachers', 'teacher_course_rel', 'course_id',
'teacher_id', string='Teachers')
Using SQL (either using Odoo API or your DBMS), you can query the junction table (or cross-reference table) teacher_course_rel to retrieve the needed columns from each table.
For instance, the query below retrieves all the teachers' names teaching the Physics course:
SELECT c.title, t.name
FROM teacher AS t
INNER JOIN teacher_course_rel AS tcr
ON t.id = tcr.teacher_id
INNER JOIN course AS c
ON tcr.course_id = c.id
WHERE c.title = 'Physics'
Please note that I have used an SQL INNER JOIN which returns rows from the two tables only when the conditions are met (i.e. the two INNER JOIN conditions and the WHERE condition). For your purposes, you may wish to use a different type of join depending on the information you wish to retrieve from both your tables.

Related

SQL Server - Question about Inheritance in Database Schemas

I'm having problems understanding the class table inheritance structure that you can implement using database tables. Info on class table inheritance. I have a use case where I have quite different types of persons that I need to model, but they have very minor differences. For example, all of these persons, like Student, Professor and so on, have a surname and a lastname. My first thought was to move theses attributes into a different table inside a base table like you would do in Object Oriented Programming. Here to illustrate further:
Right now, a Professor can only have one person, for example, otherwise it wouldn't make sense in my use case. Also, I have a school table that has two foreign keys, one for the Professor and one for the Student. Lets assume that a school can also have only one professor and one student. This is not the real use case that I have. This example just represents the relation in my real use case which would be too much to explain here.
What I don't understand is how you would collect data based on that. I'm trying to make a SQL Server View where I want to load the Person of the Professor and the Person of the Student from the view point of the School Table. For example:
SELECT
School.professor_id
surname,
lastname
FROM dbo.School AS school
INNER JOIN dbo.Professor as prof
ON school.professor_id = prof.ID
INNER JOIN dbo.Person as prof_person
ON prof.person_id = prof_person.ID
I can output the surname and lastname of the professor, but now I am stuck since I can't figure out how to get the person of the student.
A subtype table typically shares a key with the supertype table, instead of having its own PK and a FK. EG Student.ID is both the PK and the FK.
Then just join Student>Person in addition to Professor>Person, eg
SELECT
School.Id,
prof_person.surname prof_surname,
student_person.surname student_surname
FROM dbo.School AS school
INNER JOIN dbo.Professor as prof
ON school.professor_id = prof.ID
INNER JOIN dbo.Person as prof_person
ON prof.ID = prof_person.ID
INNER JOIN dbo.Student as student
ON school.student_id = student.ID
INNER JOIN dbo.Person as student_person
ON student.ID = student_person.ID
INNER JOIN is associative, so no need for special ordering or parentheses.

SQL query to select records that have one value in a column but missing another value

I have a database that has two tables. One holds the name of the classes a student can take (class_id, class_desc) and the other has the students information (id, fname, lname, class_id). I join the tables to get a roster of who is taking what class by joining on the class_id. How do I go about getting a roster of students that are taking class 'cl_2055' but not taking class 'cl_6910'?
You really need to change your schema if you can. You should have three tables. Student, Class and StudentClass, (StudentClass contains a pointer to each of the other tables.
But if you insist on using the schema you have...
SELECT
*
FROM
students
WHERE
class_id = 'cl_2055'
AND id NOT IN (SELECT id FROM students where class_id = 'cl_6910')
This assumes the id is not unique, and you are using ID to represent students. If you are using ID to represent records, then you will need the second approach:
SELECT
*
FROM
students students_in_2055
WHERE
class_id = 'cl_2055'
AND NOT EXISTS (
SELECT 1
FROM students students_in_6910
WHERE students_in_6910.class_id = 'cl_6910'
AND students_in_2055.fname = students_in_6910.fname
AND students_in_2055.lname = students_in_6910.lname
)
I like to use aggregation for this purpose
select si.fname, si.lname
from studentinformation si
where ci.classid in ('cl_2055', 'cl_6910')
group by si.fname, si.lname
having min(ci.classid) = 'cl_2055' and max(ci.classid) = 'cl_2055';
First, this assumes that the class identifiers are the ids and not the description (seems logical to me). If they are the descriptions, then you need to join in the class information.
How does this work? The where clause filters down to students who might be in both classes. The group by aggregates to a single row per student. And the having keeps students who are only in "cl_055".

Access SQL Query on same table

I have two tables: one called EMP_Names which simply stores ID and Employee_Name and another table called EMP_Main which stores the main data and which refers to EMP_Names via IDs. Amongst other fields EMP_Main has fields called Technician_Name_ID and Leader_Name_ID which is related to EMP_Names. My problem is this: how can i run a query where both Technician_Name_ID and Leader_Name_ID resolve to Names? In other words both ID fields refer to the same EMP_Names.ID but I can only establish one relationship between the two tables.
Don't know if I'm clear because it's difficult to explain ...
You can use join but you need multiple joins.
select em.*, ent.name as technician, enl.name as leader
from (emp_main as em left join
emp_names as ent
on em.technician_name_id = ent.id
) left join
emp_names as enl
on em.leader_name_id = enl.id;
These are left joins in case the fields are not populated for all rows.

Prevent slow INNER JOIN in Django model calls when unnecessary

Is it possible to prevent Django from using INNER JOIN in SQL relationship queries when unnecessary?
I have the two tables:
class Author(models.Model):
name = models.CharField(max_length=50, primary_key=True, db_index=True)
hometown = models.CharField(max_length=50)
class Book(models.Model):
title = models.CharField(max_length=50, primary_key=True, db_index=True)
author = models.ForeignKey(Author, db_index=True)
The author table has more than 50 million rows, which makes requests such getting all the books of one author, Book.objects.filter(author_id='John Smith'), incredibly slow (about 20 sec). However, when I use raw SQL to achieve the same result, the query is almost instant: SELECT * FROM books WHERE author_id='John Smith';.
Using result.query I have found that Django is slower because it runs a INNER JOIN query on the entire table:
SELECT books.title, books.author_id FROM books INNER JOIN authors
ON (books.author_id = authors.name) WHERE books.author_id = 'John Smith';
Is there a way to make Django avoid the INNER JOIN in cases such as this when it isn't necessary?
I would like to avoid using raw SQL queries if at all possible as this database structure is highly simplified.
The solution turned out to be removing a class Meta option:
class Book(models.Model):
(...)
class Meta:
ordering = ['author', 'title']

SQL query that limits results based on appearance in other tables

I'm a SQL novice, but need to write some SQL statements for a Java program that has to interact with a database. Our Java textbook covers only very basic SQL commands, and I am having trouble getting a more advanced (by my standards) one to work.
Here's the situation:
The database has 5 tables.
Teacher: TeacherID (PK), LastName
Class: ClassID (PK), Description
Room: Building, Room Number, PK is the combo of those two
TeachingAssignments: TeacherID(FK), ClassID(FK)
ClassRoomAssignments: ClassID(FK), Building, Room Number(combo is FK)
I need to give just the LastName, ClassID, and Building of only those teachers, classes, and rooms that are fully assigned. I.e., if a class both has a teacher and a room assignment, then I need to give that class's ID, the assigned teacher's last name, and the assigned building.
I have little idea how to proceed.
I've been playing around with statements like the following but they aren't working for me:
SELECT Teacher.LastName, Class.ClassID, Room.Building
FROM Teacher, Class, Room, TeachingAssignments, ClassRoomAssignments
WHERE Teacher.TeacherID = TeachingAssignments.TeacherID
AND Room.Building = ClassRoomAssignments.Building
AND Class.ClassID = TeachingAssignments.ClassID
AND Class.ClassID = ClassRoomAssignments.ClassID
Can anyone help? Thanks!
Your problem is that you need to add the respective joins for your table.
instead of doing:
SELECT Teacher.LastName, Class.ClassID, Room.Building
FROM Teacher, Class, Room, TeachingAssignments, ClassRoomAssignments
WHERE Teacher.TeacherID = TeachingAssignments.TeacherID
AND Room.Building = ClassRoomAssignments.Building
AND Class.ClassID = TeachingAssignments.ClassID
AND Class.ClassID = ClassRoomAssignments.ClassID
you need something like that
SELECT Teacher.LastName, Class.ClassID, Room.Building
FROM
Teacher INNER JOIN TeachingAssignments
ON Teacher.TeacherID = TeachingAssignments.TeacherID
INNER JOIN Class
ON Class.ClassID = TeachingAssignments.ClassID
INNER JOIN ClassRoomAssignments
ON Class.ClassID = ClassRoomAssignments.ClassID
INNER JOIN Room
ON Room.Building = ClassRoomAssignments.Building
As you can see every INNER Join is followed by it respective ON clause which is in charge of designing which element is going to be joined.