Translating SQL by Django ORM for INNER JOIN - inner-join

There are 2 tables like below
Employee Table
Branch Table
Branch Table has a foreign key mgr_id which relates to Employee table. The field emp_id in Employee table is related to mgr_id. Now I did a basic INNER JOIN by below SQL query and it showed correct results.
select blog_employee.emp_id, blog_employee.first_name, blog_branch.branch_name
from blog_employee
join blog_branch
on blog_employee.emp_id = blog_branch.mgr_id ;
SQL query result
For Django ORM I tried to replicate this but cannot as I have to use branch table first as it contains the foreign key. I used the below query but it does not show correct results like SQL query above
myquery16 = branch.objects.select_related('mgr_id')
It shows a different join than INNER JOIN which is LEFT OUTER JOIN and I get 4 rows because right table becomes the employee I suppose, whereas in SQL query left table is employee.
Please help me attain or replicate the raw sql query as it works correctly but it seems I can use select_related on branch only as it has the foreign key and making branch a left table but according to sql query it is a right table.
Django query above gives all the entire columns from both tables. This is the output below showing it as LEFT OUTER JOIN when I execute "myquery16"
SELECT "blog_branch"."branch_id", "blog_branch"."branch_name", "blog_branch"."mgr_id",
"blog_branch"."mgr_start_date", "blog_employee"."emp_id", "blog_employee"."first_name",
"blog_employee"."last_name", "blog_employee"."birth_day", "blog_employee"."sex",
"blog_employee"."salary", "blog_employee"."super_id", "blog_employee"."branch_id"
FROM "blog_branch" **LEFT OUTER JOIN** "blog_employee" ON ("blog_branch"."mgr_id" = "blog_employee"."emp_id")

I found the solution. The LEFT OUTER JOIN can be forced to INNER JOIN.
The LEFT OUTER JOIN was giving null results also as it was not the perfect common result of say between set A and B.
Django which produced LEFT OUTER JOIN gave result set like this:
Incorrect result
I corrected the ORM query to this below:
myquery16 = branch.objects.filter(mgr_id__isnull=False, mgr_start_date__isnull=False).select_related('mgr_id').annotate(emp_id=F('mgr_id__emp_id'),first_name=F('mgr_id__first_name'))
It worked perfect stating as INNER JOIN. Result set is: Correct result with above query
If in above Django query you replace annotate by .values(), it will restrict to columns you desire.
Here is the query seen in console:
SELECT "blog_branch"."branch_name", "blog_branch"."mgr_id" AS "emp_id", "blog_employee"."first_name" AS "first_name" FROM "blog_branch" INNER JOIN "blog_employee" ON ("blog_branch"."mgr_id" = "blog_employee"."emp_id") WHERE ("blog_branch"."mgr_id" IS NOT NULL AND "blog_branch"."mgr_start_date" IS NOT NULL)
3
Below are the models for the table:
class branch(models.Model):
branch_id = models.IntegerField(primary_key=True, validators=[validatePositive])
branch_name = models.CharField(max_length=40, null=False)
mgr_id = models.ForeignKey("employee", to_field = "emp_id", db_column='mgr_id', on_delete=models.SET_NULL, null=True, validators=[validatePositive])
mgr_start_date = models.DateField(auto_now_add=True, null=True)
class employee(models.Model):
MALE = 'M'
FEMALE ='F'
SEX_CHOICES = [
('M', 'F'),
]
emp_id = models.IntegerField(primary_key=True, validators=[validatePositive]) # though null not needed here
first_name = models.CharField(max_length=40, null=False)
last_name = models.CharField(max_length=40, null=False).............

Related

Create stored procedure and write a query for joining multi table based on columns in SQL Server

I am beginner to SQL, this is my first exercise to create a stored procedure​ in SQL. I need to get all the rows of all the persons with columns FirstName, MiddleName, LastName, email address, phone number and phonenumber type.
I have to join (required to use join) these 4 tables Person.person, person.personphone, person.phonenumbertype, person.emailaddress and retrieve the columns mentioned above.
The data I am using is the AdventureWorks 2016 SQL Server sample database, which has around 20k rows.
I tried inner joining on two tables to start with and the execution seems never ending.
select FirstName as firstname
from Person.Person
inner join person.EmailAddress on Person.Person.BusinessEntityID = Person.EmailAddress.BusinessEntityID
Thanks allmhuran and marc_s for the corrections.
Advice any link or suggestions on how I can get solution to this query.
You need something like this:
-- select the columns you want
SELECT
p.FirstName, p.MiddleName, p.LastName,
pe.EmailAddress, pp.PhoneNumber, pnt.Name AS PhoneNumberType
FROM
-- this is your "base" table - where most of the info exists
Person.Person p
INNER JOIN
-- join to the e-mail table - based on "BusinessEntityID", to get e-mail address
Person.EmailAddress pe ON pe.BusinessEntityID = p.BusinessEntityID
INNER JOIN
-- join to the person phone table - based again on "BusinessEntityID", to get phone number
Person.PersonPhone pp ON pp.BusinessEntityID = p.BusinessEntityID
INNER JOIN
-- join the PersonPhone table to the PhoneNumberType table, to get the type of phone
Person.PhoneNumberType pnt ON pnt.PhoneNumberTypeID = pp.PhoneNumberTypeID
You should always use proper / meaningful aliases for your tables - this makes your list of columns being selected, and your JOIN conditions, just so much more readable!

How to create an association with the last record of an other table

I'm working on an application for iceskaters with cakephp. A part of my database shema is like this :
Nations-(1,n)-Skaters-(1,n)-Participations-(n,1)-Competitions
Participations has a rank field and Competitions has a date field
I want to have an hasOne association from Skaters to the last Participation (of this skater) according to the date field in the table Competitions. I need that in model because i want to order Skaters by the last Participation or by the rank obtained during the last participation.
I don't know if it is possible with cakephp v3.x
In MySQL i write a query that seems to works :
Select s.id, c.title, c.date, p.id, p.rank
from
(
SELECT skater_id, max(competitions.date) as maxdate
FROM `participations`
inner join competitions on competitions.id = participations.competition_id
group by skater_id
) as x
inner join participations as p on p.skater_id = x.skater_id
inner join competitions as c on c.id = p.competition_id
inner join skaters as s on x.skater_id = s.id and maxdate = c.date
I've found a very usefull post but i'm not able to adapt it to my case (filtering field in third table not second one). The only result was : An Internal Server Error Occurred. So too dificult for me to debug without information.
Regards

Querying multiple tables two being junction tables

I am trying to write a sql query that queries records from multiple tables which involved junction tables. The Userprofile table has relationship with Role and team table and one to one relationship with TimeZone table.
I am trying to achieve a query that will pull records from UserProfile table as well relevant records from Role , team and timezone table. I have tried to write a query and it is getting overly complex. Could somebody verify my query and tell me the right way to do it
The tables are as follows
UserProfile table
[EmployeeID]
[Forename]
[Surname]
[PreferredName]
[DefaultLanguageCode]
[DefaultCountryCode]
[TimeZoneID]
[Domain]
[NetworkID]
Team table
[TeamID]
[CountryCode]
[TeamName]
[TeamDescription]
UserTeamLinkTable
[UserProfileTeamLinkID]
[TeamID]
[UserProfileID]
[isDefault]
[isActive]
UserRole Table
[RoleID]
[RoleDescription]
[isActive]
UserRoleLink Table
[UserProfileRoleLinkID]
[RoleID]
[UserProfileID]
[isActive]
TimeZone table
[TimeZoneID]
[TimeZoneCode]
[TimeZone]
[TimeZoneName]
Query
select
userprofile.[UserProfileID]
,userprofile.[EmployeeID]
,userprofile.[Forename]
,userprofile.[Surname]
,userprofile.[PreferredName]
,userprofile.[DefaultCountryCode]
,userprofile.[DefaultLanguageCode]
,userprofile.[TimeZoneID]
,userprofile.TeamID
,userprofile.TeamName
,userprofile.[Domain]
,userprofile.[NetworkID]
,userprofile.[EmailAddress]
,userprofile.[CreatedDate]
,userprofile.[CreatedBy]
,userprofile.[ModifiedDate]
,userprofile.[ModifiedBy]
from TimeZone tz inner join
(
select
up.[UserProfileID]
,up.[EmployeeID]
,up.[Forename]
,up.[Surname]
,up.[PreferredName]
,up.[DefaultCountryCode]
,up.[DefaultLanguageCode]
,up.[TimeZoneID]
,te.TeamID
,te.TeamName
,up.[Domain]
,up.[NetworkID]
,up.[EmailAddress]
,up.[CreatedDate]
,up.[CreatedBy]
,up.[ModifiedDate]
,up.[ModifiedBy]
from [dbo].[UserProfileTeamLink] upt
inner join UserProfile up on up.UserProfileID = upt.UserProfileID
inner join Team te on te.TeamID = upt.TeamID ) userprofile on tz.TimeZoneID = userprofile.TimeZoneID
It is hard to say without knowing what the data looks like or what the desired output looks like. You could join all of the tables without using sub queries if you are expecting multiple rows per user because of those many to many relationships.
select
up.[UserProfileID]
,up.[EmployeeID]
,up.[Forename]
,up.[Surname]
,up.[PreferredName]
,up.[DefaultCountryCode]
,up.[DefaultLanguageCode]
,up.[TimeZoneID]
,tz.TimeZone
,te.TeamID
,te.TeamName
,up.[Domain]
,up.[NetworkID]
,up.[EmailAddress]
,up.[CreatedDate]
,up.[CreatedBy]
,up.[ModifiedDate]
,up.[ModifiedBy]
,ur.RoleDescription
from UserProfile up
inner join TimeZone tz
on tz.TimeZoneID = up.TimeZoneID
inner join UserProfileTeamLink upt
on upt.UserProfileID = upt.UserProfileID
--and upt.isDefault = 1 /* default team only? */
--and upt.isActive = 1 /* active team only? */
inner join Team te
on te.TeamID = upt.TeamID
inner join UserProfileRoleLink upr /* left join if users might not have a role*/
on up.UserProfileID = upr.UserProfileId
--and upr.isActive = 1 /* active role only? */
inner join UserRole ur /* left join if users might not have a role*/
on upr.RoleId = ur.RoleId

Join Query Combining Two Tables

I need to display 3 columns from table A and one column from table B. I used the following join query to combine them but not getting the value in the expected columns.
example1 -this is working.(If I display one column from table A and one column from table B it works)
SELECT
tableA.col1(fkid),
tableB.col1
FROM tableA
INNER JOIN tableB
ON tableA.fkid = tableB.pkid;
I need to display 3 columns from table A and one column from table B the below query is not working.
SELECT
tableA.col1,
tableA.col2,
tableA.col3,
tableB.col1
FROM tableA
FULL JOIN tableB
ON tableA.fkid = tableB.pkid;
Original query:
select device.name,device.description, device.fkphonetemplate,phonetemplate.name from device inner join phonetemplate ON device.fkphonetemplate=phonetemplate.pkid;
Result:
description fkphonetemplate name
Nikhil (nkalantr) 10ce46f6-615d-4605-9f42-454225df5647 ARRAY(0xc7153b0)
Expected result should be:
description fkphonetemplate name
Nikhil (nkalantr) 10ce46f6-615d-4605-9f42-454225df5647 Standard 7960 SCCP
I don't get name from device table in the result and the name from phonetemplate table shows something as Array0X... but I need to get the name of phonetemplate like Standard 7960 as shown in expected result.
Can you refine my query or suggest what's wrong with the 2nd query?
Any reason for you to using full join instead of inner join ?
If no,try using inner join.
SELECT
a.col1,
a.col2,
a.col3,
b.col1
FROM tableA a
INNER JOIN tableB b
ON a.fkid = b.pkid;
Can you provide your database sample data , so we can clearly know what your need.

SQL Same Column in one row

I have a lookup table that has a Name and an ID in it. Example:
ID NAME
-----------------------------------------------------------
5499EFC9-925C-4856-A8DC-ACDBB9D0035E CANCELLED
D1E31B18-1A98-4E1A-90DA-E6A3684AD5B0 31PR
The first record indicates and order status. The next indicates a service type.
In a query from an orders table I do the following:
INNER JOIN order.id = lut.Statusid
This returns the 'cancelled' name from my lookup table. I also need the service type in the same row. This is connected in the order table by the orders.serviceid How would I go about doing this?
It Cancelled doesnt connect to 31PR.
Orders connects to both. Orders has 2 fields in it called Servicetypeid and orderstatusid. That is how those 2 connect to the order. I need to return both names in the same order row.
I think many will tell you that having two different pieces of data in the same column violates first normal form. There is a reason why having one lookup table to rule them all is a bad idea. However, you can do something like the following:
Select ..
From order
Join lut
On lut.Id = order.StatusId
Left Join lut As l2
On l2.id = order.ServiceTypeId
If order.ServiceTypeId (or whatever the column is named) is not nullable, then you can use a Join (inner join) instead.
A lot of info left out, but here it goes:
SELECT orders.id, lut1.Name AS OrderStatus, lut2.Name AS ServiceType
FROM orders
INNER JOIN lut lut1 ON order.id = lut.Statusid
INNER JOIN lut lut2 ON order.serviceid = lut.Statusid

Resources