I have a table where I am storing leave information of employees and I want to calculate total leaves employee have taken so far after taking every leave.
I have tried query but it is not grouping for each employee instead it keeps on adding all the previous rows values.
CREATE TABLE SampleLeave
(
ID Numeric,
EmpCode Numeric,
NoOfLeaves Numeric
);
INSERT INTO SampleLeave VALUES (1, 12, 2);
INSERT INTO SampleLeave VALUES (2, 12, 1);
INSERT INTO SampleLeave VALUES (3, 12, 3);
INSERT INTO SampleLeave VALUES (4, 1, 1);
INSERT INTO SampleLeave VALUES (5, 1, 5);
SELECT *, SUM([NoOfLeaves]) OVER (ORDER BY [ID]) Leaves FROM SampleLeave
Here is the output I am getting instead I want the Sum function to calculate the number of leaves when employee ID differs.
ID EmpCode NoOfLeaves Leaves
--------------------------------------- --------------------------------------- --------------------------------------- ---------------------------------------
1 12 2 2
2 12 1 3
3 12 3 6
4 1 1 7
5 1 5 12
Output I am expecting:
ID EmpCode NoOfLeaves Leaves
--------------------------------------- --------------------------------------- --------------------------------------- ---------------------------------------
1 12 2 2
2 12 1 3
3 12 3 6
4 1 1 1
5 1 5 6
You would required to add partition clause in order to get departmental leaves based on EmpCode
select *,
sum([NoOfLeaves]) over (partition by EmpCode order by id) Leaves
from SampleLeave
order by 1
Related
I have a table that looks like this:
id code total
1 2 30
1 4 60
1 2 31
2 2 10
2 4 11
What I'd like to do, is basically get one row per id for the sum of records for code 2 and the sum of records for all codes for that id. So something like this:
id code2_total overall
1 61 121
2 10 21
I've tried the following:
select id
, abs(sum(total) over (partition by id)) as overall
, (select sum(total) from table where code = '2' group by id) as code2_total
from table limit 1
But I'm getting multiple items in the subquery error. How can I achieve something like this?
Use group by with a regular sum and a conditional sum (i.e. using a case expression).
declare #MyTable table (id int, code int, total int);
insert into #MyTable (id, code, total)
values
(1, 2, 30),
(1, 4, 60),
(1, 2, 31),
(2, 2, 10),
(2, 4, 11);
select id
, sum(case when code = 2 then total else 0 end) code2_total
, sum(total) overall
from #MyTable
group by id
order by id;
Returns
id
code2_total
overall
1
61
121
2
10
21
Note limit 1 is MySQL not SQL Server and doesn't help you here anyway.
Note also that providing the DDL+DML as I have shown here makes it much easier for people to assist.
I am trying to join 2 tables on a row, and if that row is null, then join that row to the default row.
Table 1: Events
EventID EventName
----------- -------------
1 January
2 February
3 March
4 April
Table 2: Menus
MenuID EventID MenuVersion
---------- ----------- ---------------
1 1
2 3 2
3 4 4
4 4
What I have Tried
SELECT * FROM Events
LEFT JOIN Menus
ON Events.EventID = Menus.EventID
Output I'm Getting
EventID EventName MenuID EventID MenuVersion
----------- ------------- --------- ---------- ---------------
1 January
2 February
3 March 2 3 2
4 April 3 4 4
The default row of the Menus table in this case is the row with the highest MenuID and a null EventID.
Output I want
EventID EventName MenuID EventID MenuVersion
----------- ------------- --------- ---------- ---------------
1 January 4 4
2 February 4 4
3 March 2 3 2
4 April 3 4 4
Cross apply the default row and use its values when no row is left joined on.
DECLARE #Events TABLE (EventId INT, EventName VARCHAR(12));
DECLARE #Menus TABLE (MenuId INT, EventId INT, MenuVersion INT);
INSERT INTO #Events (EventId, EventName)
VALUES
(1, 'January'),
(2, 'February'),
(3, 'March'),
(4, 'April');
INSERT INTO #Menus (MenuId, EventId, MenuVersion)
VALUES
(1, null, 1),
(2, 3, 2),
(3, 4, 4),
(4, null, 4);
SELECT E.EventId, E.EventName, COALESCE(M.MenuId, D.MenuId) MenuId, M.EventId, COALESCE(M.MenuVersion, D.MenuVersion) MenuVersion
FROM #Events E
LEFT JOIN #Menus M ON M.EventID = E.EventID
CROSS APPLY (SELECT TOP 1 * FROM #Menus WHERE EventId IS NULL ORDER BY MenuId DESC) D;
Returns as requested:
EventId EventName MenuId EventId MenuVersion
1 January 4 NULL 4
2 February 4 NULL 4
3 March 2 3 2
4 April 3 4 4
Note: If you set out your questions like this in future with the DDL/DML statements you'll get a much faster response because it saves people from having to type it all in.
I'm working in SQL Server 2014 Management Studio.
Not really sure how to explain this but it's best if I just explain with an example.
So I've figured out how to get the next lowest ID, that is fairly simple. But once i get that row i need to take the value from it and apply it to the next highest value.
If I have 4 rows
ID value
-------------
10 50
30 200
20 75
25 100
I want to take the value each row and applying to the row with the next highest ID. So it should look like this.
ID value
-------------
10 null or 0
30 100
20 50
25 75
Since there is no row before 10 ID, that row should have a value of null or 0, doesn't matter. And the others should just follow the pattern of taking the value from the row with the next lowest ID.
You're looking for LAG():
Select Id, Lag(Value) Over (Order By Id) As Value
From YourTable;
Working demo:
Declare #YourTable Table
(
Id Int,
Value Int
);
Insert #YourTable
Values (10, 50), (30, 200), (20, 75), (25, 100);
Select Id, Lag(Value) Over (Order By Id) As Value
From #YourTable;
Results
Id Value
10 NULL
20 50
25 75
30 100
I have a table with 4 columns. The SQL fiddle for the same is as below:
CREATE TABLE Temp
(
ID INT IDENTITY(1,1),
BeginDateID INT,
EndDateID INT,
Duration INT
)
INSERT INTO Temp
VALUES(0, 2, 3),
(8, 10, 3),
(16, 17, 2),
(20, 20, 1)
SELECT * FROM Temp
This is what the actual data look like:
ID BeginDateID EndDateID Duration
1 0 2 3
2 8 10 3
3 16 17 2
4 20 20 1
Now I will pass the ID values between EndDateID of 1st row and BeginDateID of 2nd row and so on into another proc and it will return boolean value. E.g. I will pass 41893, 41894, 41895....41897, 41901, 41902....41905, 41908, 41909 one by one. On passing these values i will get either 0 or 1. If I get all 0's for a slot, i.e. if I get 0 when I pass 41908 and 41909, the next row should be clubbed and final data should look like below:
ID BeginDateID EndDateID Duration
1 0 2 3
2 8 10 3
3 16 20 3
Please let me know if any further clarification is needed.
Given a table with:
ID VALUE
-- -----
1 1
2 2
3 3
4 4
I would like to compute something like this:
ID VALUE SUM
-- ----- ---
1 1 40 -- (2-1)*2 + (3-1)*3 + (4-1)*4 + (5-1)*5
2 2 26 -- (3-2)*3 + (4-2)*4 + (5-2)*5
3 3 14 -- (4-3)*4 + (5-3)*5
4 4 5 -- (5-4)*5
5 5 0 -- 0
Where the SUM on each row is the sum of the values of each subsequent row multiplied by the difference between the value of the subsequent row and the current row.
I could start with something like this:
CREATE TABLE x(id int, value int);
INSERT INTO x VALUES(1, 1);
INSERT INTO x VALUES(2, 2);
INSERT INTO x VALUES(3, 3);
INSERT INTO x VALUES(4, 4);
INSERT INTO x VALUES(5, 5);
SELECT id, value
,SUM(value) OVER(ORDER BY id ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) AS sum
FROM x;
id | value | sum
----+-------+-----
1 | 1 | 14
2 | 2 | 12
3 | 3 | 9
4 | 4 | 5
5 | 5 |
(5 rows)
where each row has the sum of all subsequent rows. But to take it further, I would really want something like this pseudo code:
SELECT id, value
,SUM( (value - FIRST_ROW(value)) * value )
OVER(ORDER BY id ROWS BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) AS sum
FROM x;
But this is not valid. And that is the crux of the question: is there a way to reference multiple rows in the window of an analytic function? Or a different way to approach this? The example above is contrived. I was actually playing with an interesting puzzle from another post Rollup Query which led me to this problem. I am trying this in Postgresql 9.1, but not bound to that.
Not quite sure if I've understood your requirement exactly here, but the query that you want is something like
select a.id, a.value, sum(( b.value - a.value ) * b.value )
from x a, x b
where a.id < b.id
group by a.id, a.value
Hope that helps.