A challenge for you SQL lovers out there - sql-server

I'm new to the working world an am fresh out of varsity. i started working an am creating a few reports via SQL reporting services as part of my training.
Here is quite a challenge that I am stuck at. Please help me finish this query. Here is how it goes!
There are several employees in the employee_table that each have unique identifier known as the emp_id
There is a time_sheet table that consists of several activities AND THE HOURS FOR EACH ONE for the employees and references them via emp_id. Each activity has a TIMESHEET_DATE that corresponds to the day all the activities were submitted(once a month). There are several activities with the same date because all those activities were submitted on the same day.
And there is a leave table that references the employees via emp_id. In the leave table, there is a column for the amount of days they took off and the starting day (Leave_FROM) of the leave.
I must create a parameter where the user inputs the month (easy peasy)...
Now in the report, column 1 must have their name (easy), column 2 must have their totals hours for the specified month (HOURS) and column 3 must show how many days they took leave for that month specified.
It can be tricky, not everybody has a entry in the leavetable, but everybody has got activities in the Time_Sheet table.
Here is what I have gotten so far from a query, but its not really helping me.
Unfortunately, I cannot upload pictures, so here is a link
http://imageshack.com/a/img822/8611/5czv.jpg
Oh yea, my flavor of SQL is SQL Server

You have a few different things you need to attack here.
First is getting information from the employee_table, regardless of what is in the other two tables. To do this, I would left join on both of the tables.
Your second battle is, now since you have multiple rows in your time_sheet table, you are going to get a record for every time_sheet record. That is not what you want. You can fix this by using a SUM Aggregate and a GROUP BY clause.
Next is the issue that you are going to have when nothing exists in leave table and it is returning NULL. If you add an ISNULL(value,0) around your leave table field, it will return 0 when no records exist on that table (for that employee).
Here is what your query should look like (not exactly sure on table/column naming):
I changed the query to use temp tables, so totals are stored separately. Since the temp tables will hold 0 for employees that don't have time/leave, you can do an inner join on your final query. Check this out for more information on temp tables.
SELECT e.emp_id, ISNULL(SUM(ts.Hours),0)[Time]
INTO #TotalTime
FROM employee e
LEFT JOIN time_sheet ts ON e.emp_id = ts.emp_id
GROUP BY e.emp_id
SELECT e.emp_id, ISNULL(SUM(l.days),0) [LeaveTime]
INTO #TotalLeave
FROM employee e
LEFT JOIN leaveTable l ON e.emp_id=l.emp_id
GROUP BY e.emp_id
SELECT e.Emp_Id,Time,LeaveTime FROM Employee e
INNER JOIN #TotalTime t ON e.Emp_Id=t.Emp_Id
INNER JOIN #TotalLeave l ON e.Emp_Id=l.Emp_Id
DROP TABLE #TotalLeave,#TotalTime
Here is the SQL Fiddle

Left join the leave table, if nobody took leave you won't get any results.

Related

Find the Min and Max date from two tables from a sql select statement

Cant seem to wrap my head round this problem.
I have two tables one which has the following sample values:
Second table had the following values:
What i am trying to achieve is like the following:
So you can see the first table has the modules, what year and what term.
Based on these there is a start week and and end week.
The lookup table for the start and the finish unfortunatley is in a week basis and i need the begin week to match the second tables weekNo based on the season i guess and taking the start date being Sdate from that table to match what i am looking for and then the same applies to the end date.
Match the season and the endweek with the second tables WeekNo and Edate and only bring that date in.
Hope i made a bit of sense but i am hoping the third image shows what i am look for.
I've tried CTE, Group by, Partition by, order by, min, max and got nowhere :(
Dont really want to hard code anything, so was hoping you wonderful peps can help me out !!
Many thanks in advance :)
I suspect you are trying to achieve this by using one a single join between the tables - whereas what you actually need is two separate joins:
SELECT table1.module as mod_code,
table1.season as psl_code,
table2.Sdate as ypd_sdate,
table3.Edate as ypd_edate
FROM t1 as table1
JOIN t2 as table2 ON table2.yr = table1.year AND table2.season = table1.season AND table2.weekNo = table1.BeginWeek
JOIN t2 as table3 ON table3.yr = table1.year AND table3.season = table1.season AND table3.weekNo = table1.EndWeek

Issue when joining 3 temp tables

I have an issue joining 3 temp tables.
I am going to write the whole code but the thing that doesn't work is a join when selecting all three temp tables. Everything else works just fine (type just in case if someone wants to see the whole picture).
I need to join all three tables on dates to make sure I select the same inventory during the same time period. Whenever I join those three tables I either get Forecast or Actuals right, but never both.
When I type this I get Forecast correct, but Actuals incorrect a.[DMDPostDate]=u.[STARTDATE] and f.[STARTDATE]=a.[DMDPostDate] (Forecast correct 6998.649, Actuals are not correct 826)
-- AND u.[STARTDATE]=f.[STARTDATE] and f.[STARTDATE]=u.[STARTDATE] (Actuals are correct 10369, Forecast not correct 8322.315)
-- and a.[DMDPostDate]=f.[STARTDATE] (Forecast correct 6998.649, Actuals not correct)
-- AND u.[STARTDATE]=a.[DMDPostDate] (Forecast correct 6998.649, Actuals not correct)
-- AND u.[STARTDATE]=f.[STARTDATE] (Actuals are correct 10369, Forecast not correct)
-- and u.[STARTDATE]=f.[STARTDATE] and u.[STARTDATE] = a.[DMDPostDate] (Forecast correct 6998.649, Actuals not correct)
From your post - it seems fairly clear that joining STARTDATEs gets you the correct actuals, and joining DMDPostDate to either start date gets the right forecast.
Something thing to consider - u.[STARTDATE]=f.[STARTDATE] - this clause should have no impact to the A table join, what if you added this to the F table ON clause, and then u.[STARTDATE] = a.[DMDPostDate] to the A table clause
The way it's working now, you're left joining everything from table F to everything it can join to in table A based on the U.[UPC]=F.[DMDUNIT] AND U.[MASTERCHAINNAME]=F.[LOC], without any dates. It could be a challenge with the way it's evaluating the clauses as a result.
Dark horse answer - you don't need to join on any dates - actuals are correct when you aren't joining dates for the A table - when you use AND u.[STARTDATE]=f.[STARTDATE] it may be applying to the U/F join which could lower the forecast number.
You could also troubleshoot by joining the F and A tables separately to the U table to see if you're getting the expected values then.
Best guess -
SELECT
U.[UPC] AS 'Item',
U.[MASTERCHAINNAME] AS 'Chain',
U.[STARTDATE] AS 'Start Date',
U.[EVENT_TYPE] ,
U.[EVENT_NAME],
SUM(F.Forecast) AS 'Forecast',
SUM(A.HistoryQuantity) AS 'Actuals'
FROM
UDT_CKB_SNAPSHOT U
LEFT OUTER JOIN
FCSTPERFSTATIC F ON U.[UPC] = F.[DMDUNIT]
AND U.[MASTERCHAINNAME] = F.[LOC]
AND f.[STARTDATE] = u.[STARTDATE]
LEFT OUTER JOIN
HISTWIDE_CHAIN A ON U.[UPC] = a.[DMDUNIT]
AND U.[MASTERCHAINNAME] = a.[LOC]
AND a.[DMDPostDate] = u.[STARTDATE]
GROUP BY
U.[UPC], U.[MASTERCHAINNAME], U.[STARTDATE], U.[EVENT_TYPE] , U.[EVENT_NAME]

Add values to a table from a second table that only match a third table allowing for duplicates

I have been tasked to match a payment file from a bank that has invoices/payments listed on a text file I have imported into a table called Bank. I need to match the invoices to the project/projects that are associated with the invoices - call this table Invoices - which contains every invoice and project we have every had. I want to match the invoices (from Bank) to the project or multiple projects (from Invoices) to another table - called Report - so I can reconcile the payment file. I can get the correct results from Bank and Invoices with the following query
SELECT invoice
FROM Invoices INV
INNER JOIN Bank as BANK
ON INV.Invoice = BANK.Invoice_Number
The Bank file has 100 invoices and I get 169 invoices on this query. But when I try and do and update or insert
Update Report
set Invoice_Num =
(SELECT invoice
FROM Invoices INV
INNER JOIN Bank as BANK
ON INV.Invoice = BANK.Invoice_Number)
I get 0 rows updated.
I have tried to copy the Bank table to the Report table with
Insert into Report(Invoice_Num)
select Invoice_Number from Bank
but can't figure out how to account for the projects that have duplicated invoices when they are found. Of course I might be going at this entirely wrong and someone has a better way entirely.
Thanks!
Does your Report table have anything in to start with? If not, your UPDATE statement will update 0 rows, because there are 0 rows there to update. (Also, with your code as it stands, note that it would update every entry there to have the same, indeterminate value; I don't think that's what you intend.)
If you just want to copy the invoice numbers from Bank to Report, but leave out any duplicates, then your final bit of SQL just needs a DISTINCT added to do that:
Insert into Report(Invoice_Num)
select DISTINCT Invoice_Number from Bank
If you're trying to put in only invoice numbers from Bank that also match Invoice, then your first bit of code almost works, but needs to be an INSERT, not an UPDATE:
INSERT INTO report (invoice_number)
SELECT invoice
FROM Invoices INV
INNER JOIN Bank as BANK
ON INV.Invoice = BANK.Invoice_Number
Again, if you're also dealing with potential duplicates invoice numbers you only want in Report once, make that a SELECT DISTINCT to avoid them.

How to Correct This SQL CODE?

This is the question using AdvetureWorks2012.
Create a VIEW dbo.vw_Commissions to display the commissions earned last
year by all sales employees. Round the result set to two decimal places and do not include any salesperson who did not earn a commission. Include the
salesperson name, the commission earned, and the job title. Concatenate the
salesperson first and last names.
This code is not working for me. What am I screwing up?
USE AdventureWorks2012
GO
CREATE VIEW dbo.vw_Commissions
AS
SELECT
Sales.SalesPerson.SalesLastYear,
Person.Person.LastName,
Person.Person.FirstName,
HumanResources.Employee.JobTitle
FROM
Sales.SalesPerson
LEFT OUTER JOIN
Sales.SalesPerson ON Sales.SalesPerson.BusinessEntityID = Person.Person.BusinessEntityID
LEFT OUTER JOIN
Person.Person ON Person.Person.BusinessEntityID = HumanResources.Employee.BusinessEntityID
There are multiple problems with your query.
The biggest problem is it is not answering the questions asked. You are selecting SalesLastYear whereas the question asks to calculate the Commissions.
You are not filtering SalesPersons which have not earned any commission.
You need this to run only for last year.
Concatenate the FirstName and LastName.
The error you are getting is because you are using Sales.SalesPerson twice in your query. You need to give them alias names. However, I don't think you need two instances of the same table in this query. Also to use HumanResources.Employee.JobTitle column in the select list, you need to include table HumanResources.Employee in the from list.

Multi join issue

*EDIT** Thanks for all the input, and sorry for late reply. I have been away during the weekend without access to internet. I realized from the answers that I needed to provide more information, so people could understand the problem more throughly so here it comes:
I am migrating an old database design to a new design. The old one is a mess and very confusing ( I haven't been involved in the old design ). I've attached a picture of the relevent part of the old design below:
The table called Item will exist in the new design as well, and it got all columns that I need in the new design as well except one and it is here my problem begin. I need the column which I named 'neededProp' to be associated( with associated I mean like a column in the new Item table in the new design) with each new migrated row from Item.
So for a particular eid in table Environment there can be n entries in table Item. The "corresponding" set exists in table Room. The only way to know which rows that are associated in Item and Room are with the help of the columns "itemId" and "objectId" in the respective table. So for example for a particular eid there might be 100 entries in Item and Room and their "itemId" and "objectId" can be values from 1 to 100, so that column is only unique for a particular eid ( or baseSeq which it is called in table BaseFile).
Basically you can say that the tables Environment and BaseFile reminds of each other and the tables Item and Room reminds of each other. The difference is that some tables lack some columns and other may have some extra. I have no idea why it is designed like this from the beginning.
My question is if someone can help me with creating a query so that I can be able to find out the proper "neededProp" for each row in the Item-table so I can get that data into the new design?
*OLD-PART**This might be a trivial question but I can't get it to work as I want. I want to join a few tables as in the sql-statement below. If I start like this and run this query
select * from Environment e
join items ei on e.eid = ei.eid
I get like 400000 rows which is what I want. However if I add one more line so it looks like this:
select * from Environment e
join items ei on e.eid= ei.eid
left join Room r on e.roomnr = r.roomobjectnr
I get an insane amount of rows so there must be some multiplication going on. I want to get the same amount of rows ( like 400000 in this case ) even after joining the third table. Is that possible somehow? Maybe like creating a temporary view with the first 2 rows.
I am using MSSQL server.
So without knowing what data you have in your second query it's very difficult to say exactly how to write this out, and you're likely having a problem where there's an additional column that you are joining to in Rooms that perhaps you have forgotten such as something indicating a facility or hallway perhaps where you have multiple 'Room 1' entries as an example.
However, to answer your question regarding another way to write this out without using a temp table I've crufted up the below as an example of using a common table expression which will only return one record per source row.
;WITH cte_EnvironmentItems AS (
SELECT *
FROM Environment E
INNER JOIN Items I ON I.eid = E.eid
), cte_RankedRoom AS (
SELECT *
,ROW_NUMBER() OVER (ORDER BY R.UpdateDate DESC) [RN]
FROM Room R
)
SELECT *
FROM cte_EnvironmentItems E
LEFT JOIN cte_RankedRoom R ON E.roomnr = R.roomobjectnr
AND R.RN = 1
btw,do you want column from room table.if no then
select * from Environment e
join items ei on e.eid= ei.eid
where e.roomnr in (select r.roomobjectnr from Room r )
else
select * from Environment e
join items ei on e.eid= ei.eid
left join (select distinct roomobjectnr from Room) r on e.roomnr = r.roomobjectnr

Resources