Blank Table Result - sql

I am having a problem with my database. I have replicated it using adventure works 2014.
I want to show all results where the BusinessEntityID shows more than once. So if a user has been a member of two deparments, their ID will show twice
But this is what I get with the below query.
SELECT Person.FirstName,
Person.LastName,
HumanResources.Department.Name AS CurrentDepartment,
StartDate,
EndDate
FROM AdventureWorks2014.Person.Person
JOIN HumanResources.EmployeeDepartmentHistory
ON HumanResources.EmployeeDepartmentHistory.BusinessEntityID = Person.BusinessEntityID
JOIN HumanResources.Department
ON EmployeeDepartmentHistory.DepartmentID = HumanResources.Department.DepartmentID
GROUP BY Person.BusinessEntityID,
HumanResources.Department.DepartmentID,
Person.FirstName,
Person.LastName,
HumanResources.Department.Name,
StartDate,
EndDate
HAVING COUNT(Person.BusinessEntityID) > 1
ORDER BY Person.LastName, StartDate
I remove the Having I do get returned result(the whole table). So I think I know where the problem is not what it is / how to resolve it.

Im going assume your query works ok and if you dont include the group by will bring all the employees. So you need join with a list of employees with +1 department
JOIN (SELECT P.BusinessEntityID --, COUNT(EDH.DepartmentID) for debug
FROM AdventureWorks2014.Person.Person P
JOIN HumanResources.EmployeeDepartmentHistory EDH
ON P.BusinessEntityID = EDH.BusinessEntityID
GROUP BY P.BusinessEntityID
HAVING COUNT(EDH.DepartmentID) > 1
) as list_of_employees_with_two_or_more
ON AdventureWorks2014.Person.Person.BusinessEntityID =
list_of_employees_with_two_or_more.BusinessEntityID

WITH cte AS (
SELECT Person.FirstName AS FirstName,
Person.LastName AS LastName,
Person.BusinessEntityID AS BusinessEntityID
FROM AdventureWorks2014.Person.Person
INNER JOIN HumanResources.EmployeeDepartmentHistory
ON HumanResources.EmployeeDepartmentHistory.BusinessEntityID = Person.BusinessEntityID
INNER JOIN HumanResources.Department
ON EmployeeDepartmentHistory.DepartmentID = HumanResources.Department.DepartmentID
GROUP BY Person.FirstName,
Person.LastName,
Person.BusinessEntityID
HAVING COUNT(*) > 1
)
SELECT Person.FirstName,
Person.LastName,
HumanResources.Department.Name AS CurrentDepartment,
StartDate,
EndDate
FROM AdventureWorks2014.Person.Person
INNER JOIN HumanResources.EmployeeDepartmentHistory
ON HumanResources.EmployeeDepartmentHistory.BusinessEntityID = Person.BusinessEntityID
INNER JOIN HumanResources.Department
ON EmployeeDepartmentHistory.DepartmentID = HumanResources.Department.DepartmentID
INNER JOIN cte t
ON Person.FirstName = t.FirstName AND
Person.LastName = t.LastName AND
Person.BusinessEntityID = t.BusinessEntityID

You need to do the grouping separately, what I think you really want is people with more than one record in EmployeeDepartmentHistory, e.g.
SELECT BusinessEntityID
FROM HumanResources.EmployeeDepartmentHistory
GROUP BY BusinessEntityID
HAVING COUNT(*) > 1
I think the most efficient way to integrate this into your current query is by using EXISTS:
SELECT p.FirstName,
p.LastName,
d.Name AS CurrentDepartment,
edh.StartDate,
edh.EndDate
FROM Person.Person AS p
JOIN HumanResources.EmployeeDepartmentHistory AS edh
ON edh.BusinessEntityID = p.BusinessEntityID
JOIN HumanResources.Department AS d
ON d.DepartmentID = edh.DepartmentID
WHERE EXISTS
( SELECT 1
FROM HumanResources.EmployeeDepartmentHistory AS edh2
WHERE edh2.BusinessEntityID = p.BusinessEntityID
HAVING COUNT(*) > 1
)
ORDER BY p.LastName, StartDate

Related

Select value from 2 tables with condition

I want to select values Employee ID, employee first name, project name from tables employee and project of the employee assigned to more than one project.
Thanks everybody I can solve them and sorry about this question is not clear
You must use a JOIN
select EmplyoeeID, FirstName, ProjectName
from EmployeeDetail
join ProjectDetail on EmplyoeeDetailID = EmployeeID
where (select count(*) from ProjectDetail where EmplyoeeDetailID = EmployeeID) > 1
Please read more about joins here: https://www.w3schools.com/sql/sql_join.asp
Try this (a simple INNER JOIN)
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
If you want only employees with more than 1 project
SELECT e.EmployeeID, e.firstName, p.ProjectName
FROM Employee e
JOIN ProjectDetail p
ON e.EmployeeID = p.EmployeeDetailID
WHERE
(SELECT COUNT(1) FROM ProjectDetail p2
WHERE p2.EmployeeDetailID = p.EmployeeDetailID) > 1
A window function is probably the most efficient
SELECT
e.EmployeeID,
e.firstName,
p.ProjectName
FROM Employee e
JOIN (
SELECT p.*,
count = COUNT(*) OVER (PARTITION BY p.EmployeeDetailID)
FROM ProjectDetail p
) p ON e.EmployeeID = p.EmployeeDetailID AND p.count > 1;

Retrieving records with inner joins

My assignment is to get the the First name, Middle name and Last name for all Customers that have had an order before '2012-09-30' and after '2013-09-30'. I'm using the AdventureWorks2017 as a sample DB
Table: Sales.SalesOrderHeader
[SalesOrderID]
,[RevisionNumber]
,[OrderDate]
,[DueDate]
,[ShipDate]
,[Status]
,[OnlineOrderFlag]
,[SalesOrderNumber]
,[PurchaseOrderNumber]
,[AccountNumber]
,[CustomerID]
,[SalesPersonID]
,[TerritoryID]
,[BillToAddressID]
,[ShipToAddressID]
,[ShipMethodID]
,[CreditCardID]
,[CreditCardApprovalCode]
,[CurrencyRateID]
,[SubTotal]
,[TaxAmt]
,[Freight]
,[TotalDue]
,[Comment]
,[rowguid]
,[ModifiedDate]
Table: Person.Person
[BusinessEntityID]
,[PersonType]
,[NameStyle]
,[Title]
,[FirstName]
,[MiddleName]
,[LastName]
,[Suffix]
,[EmailPromotion]
,[AdditionalContactInfo]
,[Demographics]
,[rowguid]
,[ModifiedDate]
Table: Sales.Customers
[CustomerID]
,[PersonID]
,[StoreID]
,[TerritoryID]
,[AccountNumber]
,[rowguid]
,[ModifiedDate]
My Query
SELECT DISTINCT person_table.FirstName,
person_table.MiddleName,
person_table.LastName
FROM Sales.SalesOrderHeader as sales_order_table
inner join Sales.Customer as sales_customer_table
on (sales_customer_table.CustomerID = sales_order_table.CustomerID
and sales_order_table.OrderDate <= '2012-09-30' )
inner join Sales.Customer as sales_customer_table2
on (sales_customer_table2.CustomerID = sales_order_table.CustomerID
and sales_order_table.OrderDate >= '2013-06-30' )
inner join Sales.Customer as match_result
on (match_result.CustomerID = sales_customer_table2.CustomerID)
inner join Person.Person as person_table
on (person_table.BusinessEntityID = match_result.PersonID)
In this current state returns no rows and im unsure where the problem is
[UPDATE]
Found a relatevly good solution to the problem by editing Bilal Fakih answer
SELECT DISTINCT person_table.FirstName,
person_table.MiddleName,
person_table.LastName,
count(*) as Total_Instanses
FROM Sales.SalesOrderHeader as sales_order_table
inner join Sales.Customer as sales_customer_table
on (sales_customer_table.CustomerID = sales_order_table.CustomerID)
inner join Person.Person as person_table
on (person_table.BusinessEntityID = sales_customer_table.PersonID)
WHERE sales_order_table.OrderDate NOT BETWEEN '2012-09-30' AND '2013-06-30'
GROUP BY person_table.FirstName,
person_table.MiddleName,
person_table.LastName
HAVING count(*) >= 2
The suggestion was good but it woud return records that only had one instance. Im running into a few corner cases now. For example If a person has made 2 Orders that are bewfore 2012 or after 2013 will still be shown. The result im looking for is for a person to show up only when he has made orders before AND after the given dates
Try this, I'm not sure if it works I don't have the dataset to test, but it should
SELECT DISTINCT person_table.FirstName,
person_table.MiddleName,
person_table.LastName
FROM Sales.SalesOrderHeader as sales_order_table
inner join Sales.Customer as sales_customer_table
on (sales_customer_table.CustomerID = sales_order_table.CustomerID
inner join Person.Person as person_table
on (person_table.BusinessEntityID = match_result.PersonID)
WHERE sales_order_table.OrderDate NOT BETWEEN '2012-09-30' AND '2013-06-30'
You could simply this using below. Also your dates filter was not correct.
SELECT DISTINCT p.FirstName,
p.MiddleName,
p.LastName
FROM Sales.SalesOrderHeader as s
INNER JOIN Sales.Customer as c
ON c.CustomerID = s.CustomerID
INNER JOIN Person.Person as p
ON p.BusinessEntityID = c.PersonID)
WHERE s.OrderDate >= '2012-09-30' <----- add this
AND s.OrderDate <= '2013-06-30' ) ---- and this
My assignment is to get the the First name, Middle name and Last name for all Customers that have had an order before '2012-09-30' and after '2013-09-30'.
One method uses aggregation:
SELECT p.FirstName, p.MiddleName, p.LastName
FROM person_table p JOIN
Sales.Customer c
ON p.BusinessEntityID = c.PersonID JOIN
Sales.SalesOrderHeader so
ON c.CustomerID = so.Cus tomerID
GROUP BY p.FirstName, p.MiddleName, p.LastName
HAVING MIN(so.OrderDate) < '2020-09-30' AND
MAX(so.OrderDate) >'2013-06-30';
I will say that this condition looks suspicious:
ON p.BusinessEntityID = c.PersonID
However, that is what you use in your query. I would expect the person table to have an id called something like PersonId.

Stored procedure that selects from multiple group the results then order each group in descending order?

Here is the list of tables:
My Tables
I will like to create a stored procedure that will use the athleteId as parameter for the query and select all the columns in the result table and a few columns in each of the other tables Group the results by the EventName of the Event Table then order the groups by the Mark in descending order from the Result table and select the last record for each event.
I have search the net and tried various queries but cant seem to get the results I need.
This is hat I created. It retrieves all the info I need but I just don't seem to be able to group, order and select the lowest mark.
SELECT
a.Id as AthleteId, a.FirstName AS FirstName, a.LastName AS LastName,
a.BirthDate AS BirthDate, a.IsMale AS Male,
a.Phone AS Phone, a.Email AS Email,
p.FirstName AS ParentName, p.LastName AS ParentSurname,
p.Phone AS ParentPhone, p.Email AS ParentEmail,
ad.Street1 AS Street1, ad.Street2 AS Street2, ad.Town AS Town,
ad.Parish AS Parish, ad.Country AS Country,
s.SchoolName AS School, s.Phone AS SchoolPhone,
s.[Location] AS SchoolLocation,
c.FirstName AS CoachName, c.LastName AS CoachSurname,
c.Phone AS CoachPhone, c.Email AS CoachEmail,
m.MeetName AS MeetName,
m.StartDate AS StartDate, m.EndDate AS EndDate, m.[Location] AS MeetLocation,
e.EventName AS EventName,
r.Mark AS EventMark, r.Wind AS Wind, r.PerfDate AS PerfDate
FROM
dbo.Result r
INNER JOIN
dbo.[Event] e ON e.Id = r.EventId
INNER JOIN
dbo.Meet m ON m.Id = r.MeetId
INNER JOIN
dbo.Athlete a
JOIN
dbo.Parent p ON p.Id = a.ParentId
JOIN
dbo.[Address] ad ON ad.Id = a.AddressId
JOIN
dbo.Coach c ON c.Id = a.CoachId
JOIN
dbo.School s ON s.Id = a.SchoolId
ON a.Id = r.AthleteId
WHERE
r.AthleteId = #AthleteId
When I try adding the group by it shows an error.
Can anyone help me with this?
A quick-and-dirty way to do this in SQL Server is:
select top (1) with ties . . .
. . .
. . .
order by row_number() over (partition by r.eventid order by r.mark desc)

Working on Adventureworks2014, not joining correctly

Using SqlServer 2014.
Below is my good and bad code. I am trying to query the HumanResources.Employee db, and include two things with it, the most recent pay upgrade in pay from the HumanResources.EmployeePayHistory in the form of "most recent date", and the First, Middle, and Last Names from the Person.Person file.
I was able to query the employee data and include the names successfully.
select b.*,(a.FirstName +' '+ isnull(a.MiddleName,'')+' '+a.LastName) as WHOLE_NAME
from Person.Person a
join HumanResources.Employee b
on a.BusinessEntityID = b.BusinessEntityID
I was able to then figure out how to get the correct date format out of the pay history file...
Select Convert(VarChar(10),ModifiedDate,101) as Date
From HumanResources.EmployeeDepartmentHistory
I know that I can find the MAX date for each pay upgrade like this:
Select BusinessEntityID, MAX(ModifiedDate) as MostRecent
From HumanResources.EmployeePayHistory
Group By BusinessEntityID
But when I try to combine three tables, my brain pretty much melts and I keep blowing it. Here is my mess:
Select Convert(VarChar(10),c.ModifiedDate,101) as Date, b.*,(a.FirstName +' '+ isnull(a.MiddleName,'')+' '+a.LastName) as WHOLE_NAME
From Person.Person a inner join
HumanResources.Employee b on a.BusinessEntityID = b.BusinessEntityID
inner join
(Select BusinessEntityID, MAX(ModifiedDate) as MostRecent
From HumanResources.EmployeePayHistory
Group By BusinessEntityID)
HumanResources.EmployeePayHistory c
on c.businessEntityID = a.BusinessEntityID
Can you help me fix this final three-table join attempt?
Many thanks.
Change this Convert(VarChar(10),c.ModifiedDate,101) as Date to this Convert(VarChar(10),c.MostRecent,101) as Date (since you have named the column you are referencing as MostRecent)
Change your alias on your derived table join to simply c
Whole query:
SELECT Convert(VarChar(10),c.MostRecent,101) as Date,
b.*,
(a.FirstName +' '+ isnull(a.MiddleName,'')+' '+a.LastName) as WHOLE_NAME
FROM Person.Person a
INNER JOIN HumanResources.Employee b on a.BusinessEntityID = b.BusinessEntityID
INNER JOIN (SELECT BusinessEntityID, MAX(ModifiedDate) as MostRecent
FROM HumanResources.EmployeePayHistory
GROUP BY BusinessEntityID
) c on c.businessEntityID = a.BusinessEntityID
I think you are overthinking this. You can do 2 easy joins and then MAX() the last pay raise from the pay history table. I don't think you need to touch the employee dept history table.
SELECT c.*
, a.businessentityid
, FirstName + ISNULL(middlename, '') + lastname AS fullname
, CONVERT(VARCHAR(10), MAX(b.ratechangedate), 101) AS last_pay_increase
FROM person.person a
INNER JOIN HumanResources.EmployeePayHistory b
ON b.BusinessEntityID = a.BusinessEntityID
INNER JOIN HumanResources.Employee c
ON c.BusinessEntityID = a.BusinessEntityID
GROUP BY c.BusinessEntityID
, c.NationalIDNumber
, c.LoginID
, c.OrganizationNode
, c.OrganizationLevel
, c.JobTitle
, c.BirthDate
, c.MaritalStatus
, c.Gender
, c.HireDate
, c.SalariedFlag
, c.VacationHours
, c.SickLeaveHours
, c.CurrentFlag
, c.rowguid
, c.ModifiedDate
, a.businessentityid
, FirstName + ISNULL(middlename, '') + lastname

Include 0 when using count() SQL Server Left Join not working

Here I have used a left join on the person table because I want to include every record in that table even if it doesn't have an associated record in the task table. How can I resolve this to include the 0's in my results?
SELECT CONVERT(NVARCHAR, COUNT(p.personID)) AS count,
CONVERT(DECIMAL(4, 2), 1.0 * COUNT(p.personID) / DATEDIFF(DAY, #startDate, #endDate)) AS average,
p.personID,
p.firstname,
p.lastname,
c.companyname
FROM Tasks t
LEFT JOIN Person p
ON p.personID = t.personID
JOIN Client c
ON c.id = p.employer
JOIN Commission m
ON m.ClientID = c.ID
WHERE t.created BETWEEN #startDate AND #endDate
AND m.owner IN ( 'John Doe' )
GROUP BY p.personID,
p.firstname,
p.lastname,
c.companyname
ORDER BY c.companyname,
count DESC
I just figured out the answer to my problem... because I put conditions in the where clause on behalf of the other tables that I joined, it filtered out what I wanted. So I changed the person table to the "driving table" and I took the conditions from the where clause and put them in the join statement as I was joining the tasks table as follows:
SELECT
convert(nvarchar, COUNT(t.personID)) AS count,
CONVERT(decimal(4, 2), 1.0*COUNT(t.personID)
/ DATEDIFF(DAY, #startDate, #endDate)
) AS average,
p.personID,
p.firstname,
p.lastname,
c.companyname
FROM Person p
LEFT JOIN Tasks t
ON t.personID = p.personID AND t.created BETWEEN #startDate AND #endDate
JOIN Client c
ON c.id = p.employer
JOIN Commission m
ON m.ClientID = c.ID AND m.owner IN ('John Doe')
GROUP BY p.personID, p.firstname, p.lastname, c.companyname
ORDER BY c.companyname, count DESC
Provide filtered input through a subquery instead of the WHERE clause:
SELECT
convert(nvarchar, COUNT(p.personID)) AS count,
CONVERT(decimal(4, 2),1.0*COUNT(p.personID) / DATEDIFF(DAY, #startDate, #endDate)) AS average,
p.personID,
p.firstname,
p.lastname,
c.companyname
FROM Person p
LEFT JOIN (
select personId from tasks
where t.created BETWEEN #startDate AND #endDate
) t
ON t.personID = p.personID
JOIN Client c
ON c.id = p.employer
JOIN Commission m
ON m.ClientID = c.ID AND m.owner IN ('John Doe')
GROUP BY p.personID, p.firstname, p.lastname, c.companyname
ORDER BY c.companyname, count DESC
Maybe not the most useful in this particular example, but if the WHERE clause is complex and filtering more than one table, this is the answer.