How would I do this conditional join in MS SQL? - sql

I searched around for conditional joins, but it seems like they're trying to do something different that what I'm trying. I'll simplify the problem a bit for the question.
I have three tables: Users, Clients, and Employees.
The Users table has two columns, AssociatedID and UserType.
UserType is either "Client" or "Employee," and AssociatedID is a corresponding ID in either the Clients or the Employees table.
The problem is, Clients and Employees both use integers for IDs, so each table could have the same ID for something completely different (as opposed to GUIDs, which would avoid this problem).
What I want is a query that will look at a row in Users and say if UserType is Employee, then JOIN AssociatedID on the Employees table's ID, and if UserType is Client, then JOIN AssocaitedID on the Clients table's ID. So if Clients and Employees both have a Name column, I could get all of the names that go with each User, regardless of if they're a Client or an Employee. I'm using SQL Server 2008 R2 if that makes a difference here.

Try this:
SELECT
COALESCE(c.Name, e.Name) AssociatedName,
...
FROM Users u
LEFT JOIN Clients c ON u.AssociatedID = c.ClientId
AND u.UserType = 'Client'
LEFT JOIN Employees e ON u.AssociatedID = e.EmployeeId
AND u.UserType = 'Employee';
SQL Fiddle demo
Or: As #Tikkes pointed out, you can do this with UNION like this:
SELECT c.Name AssociatedName
FROM Users u
INNER JOIN Clients c ON u.AssociatedID = c.ClientId
AND u.UserType = 'Client'
UNION ALL
SELECT e.Name FROM Users u
INNER JOIN Employees e ON u.AssociatedID = e.EmployeeId
AND u.UserType = 'Employee';
Updated SQL Fiddle Demo
Update: For this you have to use the CASE expression like this:
SELECT
u.AssociatedID,
CASE u.UserType
WHEN 'Client' THEN c.Name
ELSE e.Name
END AS AssociationName
FROM Users u
LEFT JOIN Clients c ON u.AssociatedID = c.ClientId
LEFT JOIN Employees e ON u.AssociatedID = e.EmployeeId;
Updated SQL Fiddle Demo using CASE

Same Senario: I have CustomerExt have SoldTo and ShipTo Code,
and if ShipTo column has value then use ShipToName in table ShipTo otherwise use CustomerName in Customer table
Select COALESCE(B.CustomerName, C.ShiptoName) as CustomerName
FROM CustomerExt A
left join Customer B ON A.SoldTo = B.CustomerCode
AND isnull(A.ShipTo,'') =''
left join ShipTo C ON A.ShipTo = C.ShipToCode
AND isnull(A.ShipTo,'') <>''

Related

Best Way to join 1 to many tables

I have two tables. First one is name of all members and second is all projects and its team members of different roles.
Table 1 : [members] id, name
Table 2 : [projects] id, proj_name, sponsor (fk1_tbl_1), proj_mgr(fk2_tbl_1) , proj_co (fk3_tbl_1)
I created a query to show the project name and names of all project roles.
I am doing three joins with two sub-queries in order to achieve this.
I want to know if there is better ways to do this (in pure sql, NOT script languages like pl/sql).
select f.proj_name, f.proj_sponsor, f.proj_mgr, e.name proj_co
from
name e,
(
select
d.proj_name, d.proj_sponsor, c.name proj_mgr, d.proj_co
from
members c,
(
select
b.proj_name, a.name proj_sponsor, b.proj_mgr mgr, b.proj_co co
from
members a, projects b
where
b.sponsor = a.id
) d
where
c.id = d.mgr
) f
where
e.id = f.proj_co
Use join and join again:
select p.*, ms.name as sponsor, mm.name as manager, mc.name as co_name
from projects p left join
members ms
on p.sponsor = ms.id left join
members mm
on p.manager = mm.id left join
members mo
on p.proj_co = mo.id;
Notes:
This uses left join in case any values are missing. The project will still be returned.
Never use commas in the FROM clause.
Always use proper, explicit, standard JOIN syntax.
Use meaningful table aliases, rather than arbitrary letters.

Creating view in phpmyadmin

When i try to create view like this CREATE VIEW data2tables AS
SELECT * FROM Employees e INNER JOIN Computers c ON e.id = c.id WHERE e.name = 'Georgi' AND c.department = 'Sales'
it gives me error saying that #1060 - Duplicate column name 'id',and i have no idea how to fix it or why does the error occur.
CREATE VIEW data2tables AS
SELECT * FROM Employees e INNER JOIN Computers c
ON e.id = c.id
WHERE e.name = 'Georgi' AND c.department = 'Sales';
#1060 - Duplicate column name 'id'
Your table Employees and the table Computers both have a column named id.
When you say SELECT * FROM Employees e INNER JOIN Computers c... you are basically saying give me every column 'Employees' AND 'Computers' so you are getting a duplicate of id (and any other column in there that may be the same name).
With a VIEW you want to select a defined set of results so I would recommend explicitly specifying the columns you want from both tables.
If you require id from both tables I would recommend giving the joined table (Computers) id column an alias...something like this:
CREATE VIEW data2tables AS
SELECT e.id, e.fieldA, e.fieldN, c.id as ComputersId, c.fieldA, c.fieldN
FROM Employees e
INNER JOIN Computers c ON e.id = c.id
WHERE e.name = 'Georgi' AND c.department = 'Sales';
That method of aliasing will also apply to any other cross-over column names you encounter.
try to specify columns for Computer's table.
CREATE VIEW data2tables AS
SELECT e.*, c.[column_name].... FROM Employees e INNER JOIN Computers c
ON e.id = c.id
WHERE e.name = 'Georgi' AND c.department = 'Sales';

querying data between three tables

Just wanted confirmation to make sure I'm doing this right before I try it. Kinda weak on joins.
I have three tables:
USER PERSONGROUPTOPERRSON PERSONGROUPS
id userId groupID
firstName groupId groupName
lastName
lastUpdated
I need all users who belong to groups with "volunteer" in the group name.
Would this query be correct?
SELECT
a.firstName, a.lastName, a.lastUpdated
FROM
user as a, persongrouptoperson as b
INNER JOIN ON
a.id = b.userId
WHERE
b.groupId
IN
(SELECT
groupID
FROM
persongroups
WHERE
groupName like '%volunteer%'
);
SELECT
a.firstName, a.lastName, a.lastUpdated
FROM
user as a
INNER JOIN persongrouptoperson as b ON
a.id = b.userId
INNER JOIN persongroups as c ON
b.groupID = c.groupID
WHERE c.groupName like '%volunteer%'
You can do this with inner joins. I added distinct in case your users can be in multiple groups with the word volunteer in it. I also recommend using more intuitive aliases for tables instead of a, b, c.
select distinct
u.firstName
, u.lastName
, u.lastUpdated
from User as u
inner join PersonGroupToPerson as pgp on u.id = pgp.userId
inner join PersonGroup as pg on pgp.groupId = pg.groupId
where pg.GroupName like '%volunteer%'
Not exactly. Try it like this:
SELECT user.firstname, user.lastname, user.lastupdated
FROM user
INNER JOIN persongrouptoperson ON user.id = persongrouptoperson.userid
INNER JOIN persongroups ON persongrouptoperson.groupid = persongroups.groupid
WHERE groupName like '%volunteer%'
The idea is to join all three tables together. You can do this pretty simply with inner joins. You just have to link the common keys. So for instance, the user id field in the user table matches the userid field in the person group to person table. Then the group id field in the person groups table matches the group id field in the person group to person table. Link them with ON statements.
Once the tables are linked, you can imagine that each row contains the user information and the group information. So your where clause can directly call out what you are looking for in that group information.

Joining two tables with specific columns

I am new to SQL, I know this is really basic but I really do not know how to do it!
I am joining two tables, each tables lets say has 5 columns, joining them will give me 10 columns in total which I really do not want. What I want is to select specific columns from both of the tables so that they only show after the join. (I want to reduce my joining result to specific columns only)
SELECT * FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
The syntax above will give me all columns which I don't want. I just want EmpName, Address from the tblEmployees table and Name, Address, project from the tbSupervisor table
I know this step:
SELECT EmpName, Address FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
but I am not sure about the supervisor table.
I am using SQL Server.
This is what you need:
Select e.EmpName, e.Address, s.Name, S.Address, s.Project
From tbEmployees e
JOIN tbSupervisor s on e.id = SupervisorID
You can read about this on W3Schools for more info.
You can get columns from specific tables, either by their full name or using an alias:
SELECT E.EmpName, E.Address, S.Name, S.Address, S.Project
FROM tbEmployees E
INNER JOIN tbSupervisor S ON E.ID = S.SupervisorID
You can use the table name as part of the column specification:
SELECT tbEmployees.EmpName, tbEmployeesAddress, tbSupervisor.Name,
tbSupervisor.Address, tbSupervisor.project
FROM tbEmployees
JOIN tbSupervisor
ON tbEmployees.ID = tbSupervisor.SupervisorID
SELECT employees.EmpName, employees.Address AS employeer address,
supervisor.Name, supervisor.Address AS supervisor address,supervisor.project
FROM tbEmployees
AS employees
JOIN tbSupervisor
AS supervisor
ON
employees.ID = supervisor.SupervisorID
You need to learn about aliases. They will make your queries more maintainable. Also, you should always use aliases when referencing columns, so your query is clear about what it is doing:
SELECT e.EmpName, e.Address, s.name, s.address as SupervisorAddress
FROM tbEmployees e JOIN
tbSupervisor s
ON e.ID = s.SupervisorID;
Note that I also renamed the second address so its name is unique.
Specify the table name and field name in your selection
SELECT tbEmployees.EmpName,
tbEmployees.Address,
tbSupervisor.[column name]
FROM tbEmployees
JOIN tbSupervisor ON tbEmployees.ID = tbSupervisor.SupervisorID
SELECT product_report.*,
product.pgroup
FROM `product_report`
INNER JOIN product
ON product_report.product_id = product.id
WHERE product.pgroup = '5'
ORDER BY product.id DESC

Calculate Percentage Of Certified Managers

I asked a similar question a few weeks ago, but now the requirements have changed.
Considering the following tables:
http://www.maroisconsulting.com/Temp/query.png
I need to create a query that returns the percentages of employees who are managers (Titles.IsManager) and who have a date in the Certified field (Employees.Certified). The results need to be grouped by the Group each store is in.
So far I have this:
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM (SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
WHERE t.IsManager
GROUP BY d.GroupId;
And then this
SELECT q.GroupId,
(SumOfcert_complete/CountOfcert_complete)*100 AS percent_certified,
Groups.GroupName
FROM qryGroupCert_base AS q
INNER JOIN Groups ON q.GroupId = Groups.GroupId;
You can see in the first query where I added the Titles table.
1) I get prompted for the IsManager, although I don't know why
2) The results coming back are not different than before I added the IsManager
Anyone see what's wrong here?
Many thanks
Within your first query, you have this subquery which includes Titles aliased as "t":
(SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
) AS d
Then, after the definition of the subquery, you have this WHERE clause:
WHERE t.IsManager
The problem is the "t" alias and IsManager column only exist within the the subquery --> they are unknown to the outer (parent) query. In cases where the Access database engine encounters something it doesn't recognize as an object name, function, literal value, or SQL keyword, it thinks that something must be a parameter ... so pops up the input box asking you to provide a value for the (IsManager) parameter.
I think you should move the WHERE clause inside the subquery definition.
SELECT d.GroupId,
Sum(d.cert_complete) AS SumOfcert_complete,
Count(d.cert_complete) AS CountOfcert_complete
FROM [SELECT DISTINCT
s.GroupId,
e.EmployeeID,
IIf(e.Certified Is Null,0,1) AS cert_complete
FROM
((Stores AS s
INNER JOIN EmployeeStores AS es ON s.StoreId = es.StoreId)
INNER JOIN Employees AS e ON es.EmployeeId = e.EmployeeID)
INNER JOIN Titles AS t ON e.TitleId = t.TitleId
WHERE t.IsManager = True
]. AS d
GROUP BY d.GroupId;
Perhaps you need to supply a criteria for t.IsManager, such as t.IsManager = TRUE. If the where clause doesn't have a value to set it equal to, Access probably isn't resolving it to the actual column, but thinks it's a query parameter.