Joining multiple tables yields duplicates - sql-server

In order to retrieve all Projects for a UserId, or all in case the user is admin, I want to join multiple tables. I'm using the statment in a TableAdapter query for MSSQL.
SELECT P.ID, P.CountryID, P.ProjectYear, P.Name, P.Objective, P.StartDate, P.EndDate, P.BaseCampaign, P.ManagerID, P.IsClosed, P.OrganisationUnitID, P.QualitativeZiele, P.QuantitativeZiele,
P.Herausforderungen, P.Learnings, P.ObjectiveQuantitativ, P.Remarks, P.ProjectOverallID, C.Name AS CountryName, O.Name AS OEName, R.RoleName
FROM wc_Projects AS P
INNER JOIN wc_OrganisationUnit AS O ON P.OrganisationUnitID = O.ID
INNER JOIN wc_Countries AS C ON P.CountryID = C.ID
INNER JOIN aspnet_Roles AS R ON C.ID = R.CountryID
INNER JOIN aspnet_UsersInRoles AS UR ON R.RoleId = UR.RoleId
WHERE (#ViewAll = 1) OR (UR.UserId = #UserId)
ORDER BY P.CountryID, P.OrganisationUnitID, P.ProjectYear DESC
In order to apply to the rather static approach for the table adapter, I start with the project.
Get all projects, resolve CountryName and OEName via FK's. Now look if you can find the role that is assoicated to the country. Then find the user that is attached to the role.
I know that this is a terrible query, but it's the only one somewhat applicable to the WebForms TableAdapter way to deal with it.
When I have a UserId that has one or multiple roles associated with countries it works. When a admin user, that has no roles with countries associated but ViewAll = 1 it breaks. I get constraint exceptions and the amount of results nearly tripple.
I tried rewriting the query, adding paranthesis and different joins. But none of it worked. How can I solve this?

Related

Understanding DISTINCT vs DISTINCT ON vs Group by

I have a query which returns a set of 'records'.
The result is always from the same table, and should always be unique. It has a set of inner joins to filter the rows down to the appropriate subset.
The query is returning roughly 10 columns.
However, I found that it was returning duplicate rows, so I added select distinct to the query, which solved the duplication problem but has significant performance issues.
My understanding is that select distinct on (records.id), id... will return the same result in this case, as all duplicates would have the same primary key, and seems to be about twice as fast.
My other tests show that group by records.id is even faster again, and seems to do the same thing?
Am I correct that all three of these approaches will always return the same set of single table records?
Also, is there an easy way to compare the results of different approaches to ensure the set is being returned?
Here is my query:
SELECT DISTINCT records.*
FROM records
INNER JOIN records parents on parents.path #> records.path
INNER JOIN record_types ON record_types.id = records.record_type_id
INNER JOIN user_roles ON user_roles.record_id = parents.id AND user_roles.user_id = _user_id
INNER JOIN memberships ON memberships.role_id = user_roles.role_id
INNER JOIN roles ON roles.id = memberships.role_id
INNER JOIN groups ON memberships.group_id = groups.id AND
groups.id = record_types.view_group_id
Any individual record can have tree of 'parent' records. This is done using the ltree plugin. Effectively, we are looking to see if the user has a role which is in a group which is defined as the 'view group' for either the current record, or any of the parents. The query is actually a function, and _user_id is being passed in.
Since you are only selecting from records, you don't need DISTINCT; the records are already distinct (I presume).
So the duplicates you encounter could be caused by all the joins, for instance if more than one role or group membership matches one of your records, the same record will be combined with each of these references.
SELECT *
FROM records r
WHERE EXISTS (
SELECT *
FROM records pa on pa.path #> r.path
JOIN record_types typ ON typ.id = r.record_type_id
JOIN user_roles ur ON ur.record_id = pa.id AND ur.user_id = _user_id
JOIN memberships mem ON mem.role_id = ur.role_id
JOIN roles ON roles.id = mem.role_id
JOIN groups gr ON mem.group_id = gr.id AND gr.id = typ.view_group_id
)
;

Display only Companies that does not supply "Beverages" in Microsoft SQL

having trouble here with SQL statement for displaying companies that does not supply beverages. Now the problem here is that there are few companies that supply both beverage and other stuff. I need it to only display companies that does not supply beverages at all. When i run my modified SQL statement, i managed to get what i want but, for those companies that supply foods as well as beverages, it is still being displayed because of my WHERE clause i set to search for C.CategoryName != 'Beverages'. I just want to remove those companies that supply both beverages and foods so i can only display those companies that purely supply only foods.
Sorry if i have some grammer mistake or anything or my question is unclear. I just don't really know how to explain professionally as it is hard to describe my problem. Thanks for those who willing to help me, i am really appreciate it. And also i do not know if these info and source codes are sufficient regarding my problem. Will provide more info/source code if needed.
Pictures of Both Category & Products table.
Category Table
Products Table
Here's the Initial statement
SELECT P.ProductName
FROM Products AS P
INNER JOIN
Categories AS C
ON
C.CategoryID = P.CategoryID
AND C.CategoryName = 'Beverages'
Result
So far here's the modified statement
SELECT S.CompanyName, P.CategoryID, C.CategoryID FROM Suppliers AS S
INNER JOIN
Products AS P
ON S.SupplierID = P.SupplierID
LEFT OUTER JOIN
Categories AS C
ON
C.CategoryID = P.CategoryID
AND C.CategoryName != 'Beverages'
Result
Answer Suggested by Martin Smith.
With adding EXCEPT Clause to the SQL statement to my modified SQL statement, i managed to get it done. Here is the Answer to my problem.
SELECT S.CompanyName FROM Suppliers AS S
EXCEPT
SELECT S.CompanyName FROM Suppliers AS S
INNER JOIN
Products AS P
ON S.SupplierID = P.SupplierID
RIGHT JOIN
Categories AS C
ON
C.CategoryID = P.CategoryID
AND C.CategoryName = 'Beverages'
WITH FOODSUPPLIERS AS
(
SELECT DISTINCT SUPPLIERID
FROM PRODUCTS P
JOIN CATEGORY C ON C.CATEGORYID = P.CATEGORYID
WHERE CATEGORYNAME <> 'Beverages'
)
SELECT S.COMPANYNAME FROM SUPPLIERS S
JOIN FOODSUPPLIERS FS ON FS.SUPPLIERID = S.SUPPLIERID
The FOODSUPPLIERS CTE identifies suppliers in PRODUCTS that are not associated with any beverage products, i.e., associated only with food products. It's then a simple matter of joining the CTE to Suppliers to get the records for these suppliers.

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.

Prevent duplicates sql server

Ok, in this query I'm extracting information from 5 tables, the table Company, Programmer, Tester, Manager and the table Contract. I will extract the Programmers', testers', and Managers' Names and Telephone Numbers, as well as the Company they work on, and this company is responsible for managing this program as a request by x person doesn't matter.
Problem is with the code below, a certain information will come out as many times as there is other information, like a programmer's Name and Tel Number will come out as many times as there are Managers and Testers on the company.
I tried with left outer join and it would give me even more results, so how can I fix this so next time a result won't be duplicated but say NULL?
SELECT DISTINCT pg.name,
pg.Tel_Nr,
Mgr.name,
Mgr.Tel_Nr,
Ts.Name,
Ts.Tel_Nr,
Pg.Name,
con.program_name
FROM Company AS Cm
INNER JOIN Programmer AS Pg ON Pg.company = Cm.name
INNER JOIN Manager AS Mg ON Mg.company = Cm.name
INNER JOIN Tester AS Ts ON Ts.company = Cm.name
INNER JOIN Contract AS Con ON Con.program_name = 'My Program'
AND Cm.name = Con.Company
Surely it would make more sense to produce a list of contact details with perhaps a job description. Something like this:
WITH Cte as (select Cm.name from
Contract as Con join Company as Cm on Cm.name = Con.Company
where Con.program_name = 'My Program')
SELECT pg.name, pg.Tel_Nr, 'Programmer' as JobTitle
FROM Cte INNER JOIN
Programmer as Pg on Pg.company = Cte.name
UNION ALL
SELECT Mgr.name, Mgr.Tel_Nr,'Manager' as JobTitle
FROM Cte INNER JOIN
Manager as Mg on Mg.company= Cte.name
UNION ALL
SELECT Ts.Name, Ts.Tel_Nr, 'Tester' as JobTitle
FROM Cte INNER JOIN
Tester as Ts on Ts.company = Cte.name
This solution deploys a Common Table Expression (labelled Cte) to avoid querying thr Company and Contract tables multiple times. Find out more.

Complex SQL Join

I am fairly new to SQL joins, but I have a tricky issue here. I have tried to resolve this on my own, and searched as well, but unsuccessful.
I have two primary SQL tables
CustProfile
ClientID || ClientName
CustTransaction
CorpID || DivID || DeptID
I need to display my output as follows:
`CorpID` `CorpIDClientName` `DivID` `DivIDName` `DeptID` `DeptIDName`
CustTransaction.CorpID join on CustProfile.ClientID to get `CorpIDClientName`
CustTransaction.DivID join on CustProfile.ClientID to get `DivIDName`
CustTransaction.DeptID join on CustProfile.ClientID to get `DeptIDName`
I hope someone can provide the join query. Thanks in advance
try this one:
SELECT a.CorpID,
b.ClientName AS CorpIDClientName,
a.DivID,
c.ClientName AS DivIDName,
a.DeptID,
d.ClientName AS DeptIDName
FROM CustTransaction a
INNER JOIN CustProfile b
on a.CorpID = b.ClientID
INNER JOIN CustProfile c
on a.DivID = c.ClientID
INNER JOIN CustProfile d
on a.DeptID = d.ClientID
Am I understanding correctly? You have Corporations, Divisions, and Departments all stored within the CustProfile table together.
So you are only joining the 2 different tables, but you need to join those 2 tables 3 separate times to get each of the different types of customer (Corp or Div or Dept)
If that's the case, what you need to do is alias the table that you are including multiple times so you can join it as if it were 3 separate tables, one for corps, one for divisions, and one for departments.
I'm not sure if the syntax would be the same in MSSQL, but for most SQL databases your join query would look something like this:
SELECT corps.ClientID CorpID, corps.ClientName CorpIDClientName,
divs.ClientID DivID, divs.ClientName DivIDName,
depts.ClientID DeptID, depts.ClientName DeptIDName
FROM CustProfile corps, CustProfile divs, CustProfile depts, CustTransaction t
WHERE t.CorpID = corps.ClientID
AND t.DivID = divs.ClientID
AND t.DeptID = depts.ClientID
That should, I think, more or less do what you want...

Resources