Querying multiple tables two being junction tables - sql-server

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

Related

Translating SQL by Django ORM for 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).............

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!

Find relationship between any table A and B in Sql Server

Suppose we have the following tables, with pretty foreign keys in place.
CREATE TABLE Person
(
Id int not null
--other stuff
)
CREATE TABLE Employee
(
Id int not null,
PersonId int not null,
UserId int null
--other stuff
)
CREATE TABLE User
(
Id int not null,
Name varchar(25) not null,
Password varchar(25) not null
--other stuff
)
CREATE TABLE Roles
(
Id int not null
--other stuff
)
CREATE TABLE UserRoles
(
UserId int not null,
RoleId int not null
--other stuff
)
What are the ways(query, additional software?) to ask
"What is the relationship between table X and Y?"
E.g. I would like to 'ask' :
What is the relationship between tables Person and Roles?
Expected answer :
Person 1:N Employee 1:1 User 1:N UserRoles N:1 Roles
Note that tables Person and Roles do not have a direct relationship. The expected result should list the tables in-between of these two.
Something like this. A diagram representation would do, but it should only have the tables involved in the relationship.
Why I can't use "Database Diagrams" in SSMS.
Creating a relevant diagram with only needed tables takes too much time looking up the references by hand.
I can't use "Add Related tables" because it makes the diagram absolutely unreadable by adding 200+ tables.
The difference from diagramming would be that I only want to input two table names.
I believe this might be what you are looking for:
select t.name as TableWithForeignKey,
c.name as ForeignKeyColumn,
t2.name as DependentOnTable,
c2.name as ReferencedColumn,
N'N:1'
from sys.foreign_key_columns as fk
inner join sys.tables as t
on fk.parent_object_id = t.object_id
inner join sys.columns as c
on fk.parent_object_id = c.object_id
and fk.parent_column_id = c.column_id
inner join sys.columns as c2
on c2.object_id = fk.referenced_object_id
and c2.column_id = fk.referenced_column_id
inner join sys.tables as t2
on t2.object_id = c2.object_id
order by TableWithForeignKey
Note that all relationships in SQL server are 1:N because
neither a 1:1 can be established: How do I create a real one-to-one relationship in SQL Server
nor a N:N relationship can be established: Foreign Key to non-primary key
If you want to setup such relationships then you can merely use the extended properties to write it down for yourself and then "manually" enforce it.

SQL for Retrieving all users and default team from CRM 2013

I need to be able to retrieve all users and the default team of the Business Unit to which they belong.
How do I identify the default team of a Business Unit apart from the same name being used for both the team and BU. Is there a flag which identifies it as a default team?
My required output is the following columns
Domain Name
Team Name + GUID of Team Name (of the default team of the
BU to which they belong).
Here is my query.
SELECT dbo_SystemUser.DomainName, (dbo_Team.Name + ' ' + dbo_Team.TeamId)
FROM (dbo_Team INNER JOIN (dbo_TeamMembership INNER JOIN dbo_SystemUser ON dbo_TeamMembership.SystemUserId = dbo_SystemUser.SystemUserId) ON dbo_Team.TeamId = dbo_TeamMembership.TeamId) INNER JOIN dbo_BusinessUnit ON dbo_Team.BusinessUnitId = dbo_BusinessUnit.BusinessUnitId
WHERE dbo_Team.Name = dbo_BusinessUnit.Name
Team table has IsDefault column which is TRUE for a BU's default team.
It's also included in the FilteredTeam view.
Query that solves the OP issue:
-- Pay attention to the FROMs, tables ignore Security Roles.
-- To respect security, query the filtered views
-- (FilteredSystemUser, FilteredTeam, FilteredTeamMembership)
-- On the other hand, querying tables is much faster
SELECT U.DomainName as [Domain Name], T.Name as [Team Name], T.TeamId as [Team ID]
FROM SystemUser U
INNER JOIN TeamMembership TM ON U.SystemUserId = TM.SystemUserId
INNER JOIN Team T ON TM.TeamId = T.TeamId
WHERE T.IsDefault = 1
This should do it.
SELECT FilteredSystemUser.domainname, FilteredTeam.name, FilteredTeam.teamid
FROM FilteredSystemUser
INNER JOIN FilteredBusinessUnit ON FilteredSystemUser.businessunitid = FilteredBusinessUnit.businessunitid
INNER JOIN FilteredTeam ON FilteredTeam.businessunitid = FilteredBusinessUnit.businessunitid
WHERE FilteredTeam.isdefault = 1
You also need to be using the Filtered Views.

How do I build a query that crosses multiple tables?

Here are my tables:
CUSTOMER
Cust_ID (PK)
Name
ORDERS
Order_ID (PK)
Cust_ID (FK)
ORDER_LINE
Order_ID (pk)
Part_ID (FK)
PART
Part_ID (PK)
Part_Description
Now I want to list the customer details, the part number and the description of the parts that each customer ordered.
How do i do this?
Thanks.
You should use "JOIN" using the FK, but from what I see you don't have a foreign key between "ORDERS" and "ORDER_LINE". Are you sure you're not missing something from the table definition, ie: ORDER_LINE should maybe have the ORDER_ID as a FK ?
Hope this helps
You can try something like
SELECT c.*,
p.*
FROM CUSTOMER c INNER JOIN
ORDERS o ON c.Cust_ID = o.Cust_ID INNER JOIN
ORDER_LINE ol ON o.Order_ID = ol.Order_Number INNER JOIN
PART p ON ol.Part_Number = p.Part_Number
Have a look at
Join (SQL)
An SQL join clause combines records from two or more tables in a
database.
SQL Joins
The JOIN keyword is used in an SQL statement to query data from two or
more tables, based on a relationship between certain columns in these
tables.
And for some graphic examples
JOIN Basics
What you need is a simple straightforward JOIN like so:
SELECT
c.Cust_ID,
c.Name,
l.Part_Number,
l.Part_Description
FROM CUSTOMER c
INNER JOIN ORDERS o ON c.Cust_ID = o.Cust_ID
INNER JOIN ORDER_LINE ol ON o.OrdeR_ID = ol.Order_Number
INNER JOIN PART l ON ol.Part_Number = l.Part_Number
You want an SQL "join", such as:
SELECT c.Name, ol.Part_Number, p.Part_Description
FROM Customer AS c
JOIN Orders AS o ON c.Cust_ID = o.Cust_ID
JOIN Order_Line AS ol ON o.Order_ID = ol.Order_Number
JOIN Part AS p ON ol.Part_Number = p.Part_Number
Be aware that without a WHERE clause, this query will return all all parts in all orders for all customers, which will really hammer the network and perform poorly on anything but a tiny database:
WHERE (c.Cust_ID = MyCustomerID)
MySQL join syntax
SQL Server join syntax

Resources