Find Employees having Pending Salary - sql

There is a table - 'EmpSalary' - with Employee ID, Salary paid date and Salary amount. When a salary is paid for an employee, an entry will be posted in this table.
I want to find out the employees whose salary is pending (means either no salary is given or partially given) upto a given month in the current year.
The entire employees are available in 'Employee' table. I am using SQL Server 2005
EmpID SalDate Amount AmtPending
------ ------- ------- ----------
1 3 Jan 2019 5000 0
2 4 Jan 2019 3000 500
3 4 Jan 2019 4000 0
1 4 Feb 2019 4500 500
3 4 Feb 2019 4000 0
1 3 Mar 2019 5000 0
Expected Result - Pending upto February
EmpID Amount
------ ------
1 500
2 4000 --500 from Jan + 3500 from Feb
Since 3 has no pending upto Feb,no need to display 3

Do you just want group by and having?
select empid, sum(amtpending)
from empsalary
group by empid
having sum(amtpending) > 0;

Related

Compare data from for specific column grouping and Update based on criteria

I have a table with the following structure:
Employee Project Task Accomplishment Score Year
John A 1 5 60 2016
John A 1 6 40 2018
John A 2 3 30 2016
Simon B 2 0 30 2017
Simon B 2 4 30 2019
David C 1 3 20 2015
David C 1 2 40 2016
David C 3 0 25 2017
David C 3 5 35 2017
I want to create a view with Oracle SQLout of the above table which looks like as follows:
Employee Project Task Accomplishment Score Year UpdateScore Comment
John A 1 5 60 2016 60
John A 1 6 40 2018 100 (=60+40)
John A 2 3 30 2016 30
Simon B 2 0 30 2017 30
Simon B 2 4 40 2019 40 (no update because Accomplishement was 0)
David C 1 3 20 2015 20
David C 1 2 40 2016 60 (=20+40)
David C 3 0 25 2017 25
David C 3 5 35 2017 35 (no update because Accomplishement was 0)
The Grouping is: Employee-Project-Task.
The Rule of the UpdateScore column:
If for a specific Employee-Project-Task group Accomplishment column value is greater than 0 for the previous year, add the previous year's score to the latest year for the same Employee-Project-Task group.
For example: John-A-1 is a group which is different from John-A-2. So as we can see for John-A-1 the Accomplishment is 5 (which is greater than 0) in 2016, so we add the Score from 2016 with the score of 2018 for the John-A-1 and the updated score becomes 100.
For Simon-B-2, the accomplishment was 0, so there will be no update for 2019 for Simon-B-2.
Note: I don't need the Comment field, it is there just for more clarification.
Use analytic functions to determine if there was a score for the previous year, and if so, add it to the UpdatedScore.
select Employee, Project, Task, Accomplishment, Score, Year,
case when lag(Year) over (partition by Employee, Project order by Year) = Year - 1
then lag(Score) over (partition by Employee, Project order by Year)
else 0
end + Score as UpdatedScore
from EmployeeScore;
This is a bit strange -- you are counting the accomplishment of 0 in one year but not the next. Okay.
Use analytic functions:
select t.*,
(case when lag(accomplishment) over (partition by Employee, Project, Task order by year) > 0
then lag(score) over (partition by Employee, Project, Task order by year)
else 0
end) + score as update_score
from t;
from t

Filter Data by Date

I have question to ask. Currently, I'm developing a payslip application. However, I stuck at 1 part of the process. I'm managed to display salary but I need to filter certain date in order for the salary to be display.
For example, for this September, the company already key in the salary on 26th Sep but user can only see it start from 28th Sep and above. So, basically, the program can show previous month payslip except for September unless user start see it on 28th Sep.
Current Output :
EMPLOYEEID MONTH YEAR SALARY
E001 7 2017 2000
E001 8 2017 2000
E001 9 2017 2000
E002 7 2017 2100
E002 8 2017 2100
E002 9 2017 2100
Expectation output:
EMPLOYEEID MONTH YEAR SALARY
E001 7 2017 2000
E001 8 2017 2000
E002 7 2017 2100
E002 8 2017 2100
Current Query Progress :
SELECT EMPLOYEEID, MONTH, YEAR, SALARY
FROM DBO.Salary
WHERE day(getdate())>=28
Today is 2017-09-29, do Sep should appear. Add the OR for when it's less than 28th
select *
from dbo.Salary s1
where day(getdate())>=28
or month(getdate()) > s1.Month

return the last row that meets a condition in sql

I have two tables:
Meter
ID SerialNumber
=======================
1 ABC1
2 ABC2
3 ABC3
4 ABC4
5 ABC5
6 ABC6
RegisterLevelInformation
ID MeterID ReadValue Consumption PreviousReadDate ReadType
============================================================================
1 1 250 250 1 jan 2015 EST
2 1 550 300 1 feb 2015 ACT
3 1 1000 450 1 apr 2015 EST
4 2 350 350 1 jan 2015 EST
5 2 850 500 1 feb 2015 ACT
6 2 1000 150 1 apr 2015 ACT
7 3 1500 1500 1 jan 2015 EST
8 3 2500 1000 1 mar 2015 EST
9 3 5000 2500 4 apr 2015 EST
10 4 250 250 1 jan 2015 EST
11 4 550 300 1 feb 2015 ACT
12 4 1000 450 1 apr 2015 EST
13 5 350 350 1 jan 2015 ACT
14 5 850 500 1 feb 2015 ACT
15 5 1000 150 1 apr 2015 ACT
16 6 1500 1500 1 jan 2015 EST
17 6 2500 1000 1 mar 2015 EST
18 6 5000 2500 4 apr 2015 EST
I am trying to group by meter serial and return the last actual read date for each of the meters but I am unsure as to how to accomplish this. Here is the sql I have thus far:
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode, PreviousReadDate
order by a.SerialNumber
I can't seem to get the MAX function to take effect in returning only the latest actual reading row and it returns all dates and the same meter serial is displayed several times.
If I use the following sql:
select a.SerialNumber, count(*) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
group by a.SerialNumber
order by a.SerialNumber
then each serial is shown only once. Any help would be greatly appreciated.
Like #PaulGriffin said in his comment you need to remove PreviousReadDate column from your GROUP BY clause.
Why are you experiencing this behaviour?
Basically the partition you have chosen - (SerialNumber,ReadTypeCode,PreviousReadDate) for each distinct pair of those values prints you SerialNumber, ReadTypeCode, MAX(PreviousReadDate). Since you are applying a MAX() function to each row of the partition that includes this column you are simply using an aggregate function on one value - so the output of MAX() will be equal to the one without it.
What you wanted to achieve
Get MAX value of PreviousReadDate for every pair of (SerialNumber,ReadTypeCode). So this is what your GROUP BY clause should include.
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode
order by a.SerialNumber
Is the correct SQL query for what you want.
Difference example
ID MeterID ReadValue Consumption PreviousReadDate ReadType
============================================================================
1 1 250 250 1 jan 2015 EST
2 1 550 300 1 feb 2015 ACT
3 1 1000 450 1 apr 2015 EST
Here if you apply the query with grouping by 3 columns you would get result:
SerialNumber | ReadTypeCode | PreviousReadDate
ABC1 | EST | 1 jan 2015 -- which is MAX of 1 value (1 jan 2015)
ABC1 | ACT | 1 feb 2015
ABC1 | EST | 1 apr 2015
But instead when you only group by SerialNumber,ReadTypeCode it would yield result (considering the sample data that I posted):
SerialNumber | ReadTypeCode | PreviousReadDate
ABC1 | EST | 1 apr 2015 -- which is MAX of 2 values (1 jan 2015, 1 apr 2015)
ABC1 | ACT | 1 feb 2015 -- which is MAX of 1 value (because ReadTypeCode is different from the row above
Explanation of your second query
In this query - you are right indeed - each serial is shown only once.
select a.SerialNumber, count(*) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
group by a.SerialNumber
order by a.SerialNumber
But this query would produce you odd results you don't expect if you add grouping by more columns (which you have done in your first query - try it yourself).
You need to remove PreviousReadDate from your Group By clause.
This is what your query should look like:
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode
order by a.SerialNumber
To understand how the group by clause works when you mention multiple columns, follow this link: Using group by on multiple columns
You will understand what was wrong with your query and why it returns all dates and the same meter serial is displayed several times.
Good luck!
Kudos! :)

Expected payments through a contracts life using MS access query?

I have the following table:
contract_ID
Contract_start_date
Contract_Duration
Contract_amount
Fixed_premium
Pay_every_month
Sample Data:
contract_ID: 5
Contract_start_date: 01/01/2014
Contract_Duration: 3 years
Contract_amount: $90.000
Fixed_premium: $15000
Pay_every_month: 6 months
There should be an access query that uses the contracts data to generate a payments schedule as follows:
Contract ID......Due Date...............Amount Due
5 01 / 01 / 2014 $15.000
5 01 / 07 / 2014 $15.000
5 01 / 01 / 2015 $15.000
5 01 / 07 / 2015 $15.000
5 01 / 01 / 2016 $15.000
5 01 / 07 / 2016 $15.000
I used this SQL statement and it's not working:
SELECT
Contracts.contract_ID,
DateAdd("m",[Pay_every_month],[Contracts]![Contract_start_date]) AS Due_Date,
Contracts.Fixed_premium AS Amount_due
FROM Contracts;
Access database file is HERE
You can accomplish your goal with Access SQL using a "numbers table". Create a table named [NumbersFromZero] containing integer values starting from zero and going as high as necessary to cover the largest number of payments for any contract, e.g.,
n
--
0
1
2
3
...
98
99
Once that is in place, if we have test data like this in [Contracts]
contract_ID Contract_start_date Contract_Duration Contract_amount Fixed_premium Pay_every_month
----------- ------------------- ----------------- --------------- ------------- ---------------
5 2014-01-01 3 90000 15000 6
then the following query
SELECT
Contracts.contract_ID,
DateAdd("m", NumbersFromZero.n * Contracts.Pay_every_month, Contracts.Contract_start_date) AS Due_date,
Contracts.Fixed_premium AS Amount_due
FROM Contracts, NumbersFromZero
WHERE NumbersFromZero.n < (Contracts.Contract_Duration * 12 / Contracts.Pay_every_month)
will return
contract_ID Due_date Amount_due
----------- ---------- ----------
5 2014-01-01 15000
5 2014-07-01 15000
5 2015-01-01 15000
5 2015-07-01 15000
5 2016-01-01 15000
5 2016-07-01 15000

How to calculate Rank SQL query

HI, I have the following table which save agent ranking on daily basis on basis of tickets status.
No. **Agent Name** **Incidents** **workorder** **Rank** **TimeStamp**
1 cedric 200 29 1 21 Jan 2011
2 poul 100 10 2 21 Jan 2011
3 dan 200 20 1 21 Jan 2011
4 cedric 100 19 2 22 Jan 2011
5 poul 200 26 1 22 Jan 2011
6 dan 150 20 2 22 Jan 2011
Now i need query which fetch ranking between two dates means if i select date between 21 jan 2011 to 22 jan 2011 then query return me agents average ranking between these two dates of agent not return the agent ranking details on date wise. I need single name of agent with his ranking.
Regards,
Iftikhar hashmi
Try
SELECT [Agent Name], AVG(RANK) FROM MY_TABLE WHERE [TimeStamp] BETWEEN DATE1 AND DATE2
GROUP BY [Agent Name]
(Update)
Thanks to Martin which reminded me I need to cast RANK.
SELECT [Agent Name], AVG(CAST(RANK AS FLOAT)) FROM MY_TABLE WHERE [TimeStamp] BETWEEN DATE1 AND DATE2
GROUP BY [Agent Name]