Alternative methodology instead of NOT IN - database

Employee Table
EmployeeId
E001
E002
E003
E004
Service Table
ServiceDate EmployeeId
4/07/2014 E001
3/07/2014 E002
3/01/2014 E004
I want to list the details of employee(s) who has/have never done any car service.
The result should be:
EmployeeId
E003
I tried outer join LEFT OUTER JOIN but it got messed up.

You can use a LEFT JOIN instead of using NOT IN, like so:
select e.*
from employee e
left join service s on e.employeeid = s.employeeid
where s.employeeid is null
The LEFT JOIN ensures that you get a result set where every employee may or may not have a matching entry in Service table. The WHERE then filters that result set to retain only those employees which do not have a corresponding entry in Service, which is equivalent to your NOT IN method.
You should understand that there is nothing wrong with using a subquery in this case, but using a join may be preferable for performance reasons. This question provides an excellent analysis of joins vs subqueries.

didNot tested, but I think it can work:
select *
from (select distinct E.*, S.employeeid serviceEmployeeid
from employee E left outer join service S on e.employeeid = S.employeeid)
where serviceEmployeeid is null
added distinct for the situation a single employee had multiple services.

I think this would produce your solution.
SELECT EmployeeId
FROM
EMPLOYEE
LEFT OUTER JOIN
SERVICE
ON (EMPLOYEE.EmployeeId = SERVICE.EmployeeId)
WHERE
SERVICE.ServiceId IS NULL
;

SELECT *
FROM Employee e
WHERE (
SELECT COUNT(*)
FROM service s
WHERE e.EmployeeId = s.EmployeeId
) = 0;
I do not recommend doing this, though.
Another solution with better performance (from Conffusion's comment)
SELECT *
FROM Employee e
WHERE NOT EXISTS (
SELECT *
FROM service s
WHERE e.EmployeeId = s.EmployeeId
);

Related

Lookup table with columns in the same joined table

In a Microsoft SQL Server Database I have a lookup table that has the following structure:
Assistants:
EmployeeId, AssistantId
Those two IDs are in a second table:
Employees:
Id, FirstName, LastName
I would like to join the two tables and list each Employee and there assistants, it could be more than one. I have tried the following which I thought would work:
select * from Assistants
join Employees
on Assistants.EmployeeId = Employees.Id AND Assistants.AssistantId = Employees.Id
However it returns nothing, any ideas how I can achieve a listing of each employee and there assistants?
You have to use the employee table twice - once to get the employee and once to get the assistant.
I'm assuming not all employees have assistants, so you should probably use left joins:
SELECT * -- You really should specify the columns names here
FROM Employees As Emp
LEFT JOIN Assistants
ON Emp.Id = Assistants.EmployeeId
LEFT JOIN Employees As Assist -- You should probably find a better name for this alias...
ON Assistants.AssistantId = Assist.Id
That will give you a list of all employees and their assistants.
If, however, you can have multiple level of assistants (i.e. the CTO have an assistant CTO and they have an assistant themselves), you will need a recursive cte.
Off the top of my head. Something like this.
Select E.ID, E.FirstName, E.LastName, TBLA.FirstName, TBLA.LastName
FROM Employees E
LEFT JOIN (
Select E.FirstName, E.LastName, A.AssistantId
from Assistants A
INNER JOIN Employees on A.AssistantId = Employees.ID
) TBLA ON TBLA.AssistantId = E.ID
where TBLA.AssistantId is NOT null

Selecting Records From 1 Table That Don't Appear In Another Table

I am hoping someone might be able to help me with this issue I am having.
I have a table of customers - let's call it Table C. And I have a second table of customers that are not to be called - let's call it Table D.
I would like to pull all of the needed information (name, address, phone, etc...) from Table C unless the customer appears in Table D.
In the example shown below, I'd like to have data returned for all customers except John Doe (ID: 1) and Fred Savage (ID: 5)
I think a RIGHT OUTER JOIN might be applicable here, but I have not used this type of join before.
Use NOT EXISTS to do this:
SELECT c.*
FROM tableC c
WHERE NOT EXISTS (
SELECT *
FROM tableD d
WHERE c.customerID = d.customerid
);
If you want to use a join then it's a left join you want with a filter for null values in the d table. A right join would have gotten you all the rows from the d table, plus the matching ones from the c table - quite the opposite of what you want, but if you had switched the tables around then you would have gotten the same result, so this:
select c.* from c
left join d on c.CustomerID = d.CustomerID
where d.CustomerID is null
is equivalent to:
select c.* from d
right join c on c.CustomerID = d.CustomerID
where d.CustomerID is null;
Personally I would prefer using either a correlated not exists query or not in (but beware of null values) as I think those convey the intent more clearly.
Select * from table.c where customer_id not in (select distinct customer_id from table.d);
Yes you want an outer join.
Try this: https://technet.microsoft.com/en-US/library/ms187518(v=SQL.105).aspx

Grouping data based on expression using CountDistinct aggregate function

I am newbie to Stack overflow and also SQL server reporting services. So please excuse me for the format of the question.
So here is the situation:
I am developing a SSRS report which needs to be grouped by an Count of Distinct product names as shown below.
I created a text box called ProdCount with an expression
COUNTDISTNCT(Fields!Product.value,"DataSet1")
which gives me the count 63 within the scope of DataSet1.
Now i need to group the data by taking product names where the above formula is >1 .
=IIF(ProdCount>1,Fields!Product.value,Nothing)
My Problem:
I tried to call the ProdCount from the calculated field since i
cant use the aggregate functions in Calculated Fields and use
the second expression by using
= ReportItems!ProdCount.value
which gives me an error FieldValue Denying ReportItems
I tried to combine the above two expressions by creating a calculated field by
IIF(CountDistinct(Fields!Product.Value,"DataSet1")>1,Fields!Product.Value,Nothing)
which gives me an error Calculated fields cannot have expressions
I tried to use Report Variables in the same way as above(1) which was not working either.
I also tried to use CROSS JOIN in the query
Select Count(Distinct(Product Name)
from Query1
Cross join
My Main Query which give me the data
which is taking more time to execute.
So Can anyone help me with solution where i can group the data by combining the above two expressions.
Please excuse me for the format. I was confused with framing question. I accept all your edits , so that i can learn in future.
Here is my code:
SELECT * FROM
--Query1 which counts the number of distinct products)
(SELECT DISTINCT COUNT(gproduct.ProductName) AS ProdCount
FROM Table1
LEFT JOIN Table4
ON Table1.column=Table1.column
LEFT JOIN Table2
ON Table3.Column = TTable1.Column
LEFT JOIN
(
SELECT Distinct Table6.Name AS ProductName,Table9.ColumnId
FROM Table6
INNER JOIN Table7
ON Table6.Column=Table7.Column
INNER JOIN Table8
ON Table7.Column=Table8.Column
INNER JOIN Table9
ON Table9.Column=Table8.Column
)gproduct
ON Table1.ColumnId=gproduct.ColumnId
GROUP BY gproduct.ColumnId,
)qProduct
CROSS JOIN
--My main Query which get data from different table including Product name
(SELECT
Upper(CASE WHEN (CASE WHEN Table4.Column =1 THEN 'Yes' ELSE 'NO' END)='YES'
THEN gab.ProductName
ELSE
Table2.productName
END) AS Product,
FROM Table1 AS ec
LEFT JOIN Table2 AS ep
ON --
LEFT JOIN Table3 AS ebrd
ON --
Left JOIN Table4 AS etpc
ON --
LEFT JOIN Table5 AS gst
ON --
LEFT JOIN
(
SELECT Distinct Table6.Name AS ProductName,Table9.ColumnId
FROM Table6
INNER JOIN Table7
ON Table6.Column=Table7.Column
INNER JOIN Table8
ON Table7.Column=Table8.Column
INNER JOIN Table9
ON Table9.Column=Table8.Column
) gab
ON Table1.ColumnId=gab.ColumnId
)QMain
Personally I would try to solve the problem in query itself instead of SSRS report. According the data you provided it would be something like:
SELECT
ProductName,
count(distinct Product)
from
YourTable
group by
ProductName
having count(distinct product) > 1
Later on creating SSRS report should be quite easy.

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.

preventing display of duplicate records in SQL server

I'm using an stored procedure in SQL server, but it is giving me some duplicate records, of course I don't have duplicate records in my database, but my stored procedure is giving me two instances of a same record, what can be wrong? how can I prevent my query from giving duplicate records?
it is my SP select clause:
select (ROW_NUMBER() OVER (ORDER BY Review.Point desc) ) as rownumber,
Business.BusinessId,Business.BName,Business.BAddress1
,Business.BAddress2,Business.BCity,Business.BState,Business.BZipCode,Business.countryCode,Business.BPhone1,Business.BPhone2,Business.BEmail,Business.Keyword
,Business.BWebAddress,Business.BCatId,Business.BSubCatId,Business.BDetail,Business.bImage,Business.UCId,Business.UCConfirm
,Business.UOId,Business.UOConfirm,Business.x,Business.y,Cat.CatName,SubCat1.SubCatName
from Business left outer join
Review on business.BusinessId=Review.BusinessId left outer join
Cat on business.BCatid=Cat.CatId left outer join
SubCat1 on business.BSubCatid=SubCat1.SubCatId '+#sql2+'
) as tbl
where rownumber between '+CONVERT(varchar, #lbound)+' and '+CONVERT(varchar, #ubound);
I don't know your data to dig in to your join logic, but if it duplicating across BusinessID, you could add another ROW_NUMBER() for the duplicates:
select (ROW_NUMBER() OVER (ORDER BY Review.Point desc) ) as rownumber,
r = ROW_NUMBER()OVER(PARTITION BY Business.BusinessId ORDER BY Business.BusinessId)
Business.BusinessId,Business.BName,Business.BAddress1
,Business.BAddress2,Business.BCity,Business.BState,Business.BZipCode,Business.countryCode,Business.BPhone1,Business.BPhone2,Business.BEmail,Business.Keyword
,Business.BWebAddress,Business.BCatId,Business.BSubCatId,Business.BDetail,Business.bImage,Business.UCId,Business.UCConfirm
,Business.UOId,Business.UOConfirm,Business.x,Business.y,Cat.CatName,SubCat1.SubCatName
from Business left outer join
Review on business.BusinessId=Review.BusinessId left outer join
Cat on business.BCatid=Cat.CatId left outer join
SubCat1 on business.BSubCatid=SubCat1.SubCatId '+#sql2+'
) as tbl
where rownumber between '+CONVERT(varchar, #lbound)+' and '+CONVERT(varchar, #ubound)
AND r = 1;
Include the reserved word DISTINCT in your query.
eg
select distinct
*
from
students s
inner join enrollments e on e.StudentId = s.Id
inner join courses c on c.Id = e.CourseId
However, unexpected duplicates in a result table is often (but not always) a clue that you have a badly formed query or a badly designed database.
Try to remove this left join
Review on business.BusinessId=Review.BusinessId left outer join
seems not needed in your query and if there are more than one review for one business ...

Resources