Trying to add total for individual for every month/year - sql

" We have two tables. One for hours which have been sent to a vendor (Master) and one for the hours we are about to send (Load). I am attempting to sum the hours based on month and year for each individual with subtotals. We want to find those individuals who have more than 300 hours for a particular month.
CREATE TABLE MasterTabletesting(
ID CHAR(9) NOT NULL
,Workdate DATE NOT NULL
,Emp CHAR(30) NOT NULL
,HoursWorked DECIMAL(18,2) NOT NULL);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','7502',24);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','21874',128);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','20160731','7502',166);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','7508',180);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','5501',180);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','20160831','21037',23);
INSERT INTO MasterTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('66','20160831','83641',22);
CREATE TABLE LoadTabletesting(
ID CHAR(9) NOT NULL
,Workdate CHAR(8) NOT NULL
,Emp CHAR(30) NOT NULL
,HoursWorked DECIMAL(18,2) NOT NULL);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('8','07312016','7500',24);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('6','07312016','21974',128);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('25','07312016','7500',166);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('72','08312016','7500',180);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('88','08312016','5507',180);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('23','08312016','21012',23);
INSERT INTO LoadTabletesting(ID,Workdate,Emp,HoursWorked) VALUES ('55','08312016','83667',22);}
The date in the load table is a char variable type which I have resolved with cast. My approach has been to place the necessary data from both tables in a view titled "Over300agtest:
SELECT ID AS 'ID'
,Employer AS 'Emp'
,month(WorkDate) AS 'Mnth'
,year(WorkDate) AS 'Yr'
,HoursworkedAS 'Hrs'
,’amt’ as ‘Table’
FROM Mastertabletesting
WHERE HoursWorked IS NOT NULL
GROUP BY ID, Employer, month(WorkDate), year(WorkDate)
UNION all
SELECT ID AS 'ID'
,Employer AS 'Emp'
,month(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE)) AS 'Mnth'
,YEAR(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE)) AS 'Yr'
,hoursworked AS 'Hrs'
,‘alt’ as ‘Table’
FROM Loadtabletesting
WHERE HoursWorked IS NOT NULL
GROUP BY ID, Employer, month(CAST((RIGHT(workdate, 4) +LEFT workdate,4)) AS DATE)), year(CAST((RIGHT(workdate, 4) + LEFT(workdate, 4)) AS DATE))
Then I am using a common table expression to find those which have over 300 hours in a particular month and then using a query to join to the CTE in order to add the employer they worked for. Any suggestions on how to add a line under the hours column for each month for the total would be greatly appreciated.
with monthsum as(
Select ID as 'ID'
, mnth as 'mnth'
, yr as 'yr'
,SUM(hrs)as 'TotalHrs'
From over300agtest
Group by ID, mnth, yr
having SUM(hrs) > 300)
Select ms.ID
,ms.mnth
,ms.yr
,emp
,hrs
,o3.[table]
,totalhrs
From monthsum ms left outer join over300agtest o3
on ms.ID = o3.ID and ms.mnth = o3.mnth and ms.yr =o3.yr
Order by ms.ID, ms.yr asc, ms.mnth asc
Here is the current output:
+----+------+------+-------+-----+-------+----------+
| ID | mnth | yr | emp | hrs | table | totalhrs |
+----+------+------+-------+-----+-------+----------+
| 25 | 7 | 2016 | 7502 | 24 | AMT | 484 |
| 25 | 7 | 2016 | 21874 | 128 | AMT | 484 |
| 25 | 7 | 2016 | 7502 | 166 | AMT | 484 |
| 25 | 7 | 2016 | 7500 | 166 | ALT | 484 |
| 72 | 8 | 2016 | 7508 | 180 | AMT | 563 |
| 72 | 8 | 2016 | 5501 | 180 | AMT | 563 |
| 72 | 8 | 2016 | 21037 | 23 | AMT | 563 |
| 72 | 8 | 2016 | 7500 | 180 | ALT | 563 |
+----+------+------+-------+-----+-------+----------+
Here is the output I am going for:
+-------+------+------+-------+-----+-------+
| ID | mnth | yr | emp | hrs | table |
+-------+------+------+-------+-----+-------+
| 25 | 7 | 2016 | 7502 | 24 | AMT |
| 25 | 7 | 2016 | 21874 | 128 | AMT |
| 25 | 7 | 2016 | 7502 | 166 | AMT |
| 25 | 7 | 2016 | 7500 | 166 | ALT |
| Total | | | | 484 | |
| 72 | 8 | 2016 | 7508 | 180 | AMT |
| 72 | 8 | 2016 | 5501 | 180 | AMT |
| 72 | 8 | 2016 | 21037 | 23 | AMT |
| 72 | 8 | 2016 | 7500 | 180 | ALT |
| Total | | | | 563 | |
+-------+------+------+-------+-----+-------+

I suggest this approach. You should be able to work out the specifics.
select convert(char(6), cast(workdate as date), 120) yearMonth
, sum(hrs) totalHours
from etc
group by convert(char(6), cast(workdate as date), 120)
having sum(hrs) > 300

Related

Find the period of occurence of a value in table

I have a table with the following data.
+------------+---------+
| Date | Version |
+------------+---------+
| 1/10/2019 | 1 |
| .... | |
| 15/10/2019 | 1 |
| 16/10/2019 | 2 |
| .... | |
| 26/10/2019 | 2 |
| 27/10/2019 | 1 |
| .... | |
| 30/10/2019 | 1 |
+------------+---------+
I need to find the period of occurrence for version in the table.
Eg:Suppose I need to get Version 1 occurence details which is present from 1/10/2019 to 15/10/2019 and from 27/10/2019 to 30/10/2019. How can i query the database for such a result?
I have tried many ways but not able to produce the desired result .I even doubt this is possible using a query!
Any inputs are highly appreciated.
Expected output:
+---------+-------------+-------------+
| Version | Period from | Period To |
+---------+-------------+-------------+
| 1 | 1/10/2019 | 15/10/2019 |
| 2 | 16/10/2019 | 26/10/2019 |
| 1 | 27/10/2019 | 30/10/2019 |
+---------+-------------+-------------+
This is gaps and Islands question.
Try this
DECLARE #SampleData TABLE ( [Date] DATE, [Version] INT)
INSERT INTO #SampleData ([Date], [Version])
VALUES
('01-10-2019', 1), ('02-10-2019', 1), ('15-10-2019', 1),
('16-10-2019', 2), ('17-10-2019', 2),('26-10-2019', 2),
('27-10-2019', 1), ('28-10-2019', 1), ('30-10-2019', 1)
SELECT
Y.[Version]
,PeriodFrom = MIN(Y.[Date])
,PeriodTo = MAX(Y.[Date])
FROM(
SELECT
X.[Version]
,X.[Date]
,ISLAND = RN-ROW_NUMBER()OVER( PARTITION BY X.[Version] ORDER BY X.[Date])
FROM(
SELECT
RN=ROW_NUMBER()OVER( ORDER BY S.[Date])
,S.[Date]
,S.[Version]
FROM
#SampleData S
) X
) Y
GROUP BY
Y.[Version], Y.ISLAND
ORDER BY
PeriodFrom
Output
Version PeriodFrom PeriodTo
1 2019-10-01 2019-10-15
2 2019-10-16 2019-10-26
1 2019-10-27 2019-10-30

T-SQL return individual values instead of cumulative value

I have a 1 table in a db that stored Incoming, Outgoing and Net values for various Account Codes over time. Although there is a date field the sequence of events per Account Code is based on the "Version" number where 0 = original record for each Account Code and it increments by 1 after each change to that Account Code.
The Outgoing and Incoming values are stored in the db as cumulative values rather than the individual transaction value but I am looking for a way to Select * From this table and return the individual amounts as opposed to the cumulative.
Below are test scripts of table and data, and also 2 examples.
If i Select where code = '123' in the test table I currently get this (values are cumulative);
+------+------------+---------+---------+---------+-----+
| Code | Date | Version | Incoming| Outgoing| Net |
+------+------------+---------+---------+---------+-----+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 150 | 0 | 150 |
| 123 | 09/01/2018 | 2 | 150 | 100 | 50 |
| 123 | 14/01/2018 | 3 | 200 | 100 | 100 |
| 123 | 18/01/2018 | 4 | 200 | 175 | 25 |
| 123 | 23/01/2018 | 5 | 225 | 175 | 50 |
| 123 | 30/01/2018 | 6 | 225 | 225 | 0 |
+------+------------+---------+---------+---------+-----+
This is what I would like to see (each individual transaction);
+------+------------+---------+----------+----------+------+
| Code | Date | Version | Incoming | Outgoing | Net |
+------+------------+---------+----------+----------+------+
| 123 | 01/01/2018 | 0 | 100 | 0 | 100 |
| 123 | 07/01/2018 | 1 | 50 | 0 | 50 |
| 123 | 09/01/2018 | 2 | 0 | 100 | -100 |
| 123 | 14/01/2018 | 3 | 50 | 0 | 50 |
| 123 | 18/01/2018 | 4 | 0 | 75 | -75 |
| 123 | 23/01/2018 | 5 | 25 | 0 | 25 |
| 123 | 30/01/2018 | 6 | 0 | 50 | -50 |
+------+------------+---------+----------+----------+------+
If I had the individual transaction values and wanted to report on the cumulative, I would use an OVER PARTITION BY, but is there an opposite to that?
I am not looking to redesign the create table or the process in which it is stored, I am just looking for a way to report on this from our MI environment.
Note: I've added other random Account Codes into this to emphasis how the data is not ordered by Code or Version, but by Date.
thanks in advance for any help.
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO
CREATE TABLE [dbo].[Table1]
(
[Code] CHAR(3)
,[Date] DATE
,[Version] CHAR(3)
,[Incoming] DECIMAL(20,2)
,[Outgoing] DECIMAL(20,2)
,[Net] DECIMAL(20,2)
);
GO
INSERT INTO [dbo].[Table1] VALUES
('123','2018-01-01','0','100','0','100'),
('456','2018-01-02','0','50','0','50'),
('789','2018-01-03','0','0','0','0'),
('456','2018-01-04','1','100','0','100'),
('456','2018-01-05','2','150','0','150'),
('789','2018-01-06','1','50','50','0'),
('123','2018-01-07','1','150','0','150'),
('456','2018-01-08','3','200','0','200'),
('123','2018-01-09','2','150','100','50'),
('789','2018-01-10','2','0','0','0'),
('456','2018-01-11','4','225','0','225'),
('789','2018-01-12','3','75','25','50'),
('987','2018-01-13','0','0','50','-50'),
('123','2018-01-14','3','200','100','100'),
('654','2018-01-15','0','100','0','100'),
('456','2018-01-16','5','250','0','250'),
('987','2018-01-17','1','50','50','0'),
('123','2018-01-18','4','200','175','25'),
('789','2018-01-19','4','100','25','75'),
('987','2018-01-20','2','150','125','25'),
('321','2018-01-21','0','100','0','100'),
('654','2018-01-22','1','0','0','0'),
('123','2018-01-23','5','225','175','50'),
('321','2018-01-24','1','100','50','50'),
('789','2018-01-25','5','100','50','50'),
('987','2018-01-26','3','150','150','0'),
('456','2018-01-27','6','250','250','0'),
('456','2018-01-28','7','270','250','20'),
('321','2018-01-29','2','100','100','0'),
('123','2018-01-30','6','225','225','0'),
('987','2018-01-31','4','175','150','25')
;
GO
SELECT *
FROM [dbo].[Table1]
WHERE [Code] = '123'
GO;
USE [tempdb];
IF EXISTS ( SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'Table1'
AND TABLE_SCHEMA = 'dbo')
DROP TABLE [dbo].[Table1];
GO;
}
Just use lag():
select Evt, Date, Version,
(Loss - lag(Loss, 1, 0) over (partition by evt order by date)) as incoming,
(Rec - lag(Rec, 1, 0) over (partition by evt order by date)) as outgoing,
(Net - lag(Net, 1, 0) over (partition by evt order by date)) as net
from [dbo].[Table1];

Sql - Row as column

I have data in below format, around 8 to 9 departments, for each department few questions.
| Department | NoOfCases | Question | Rate |
+============+===========+==========+======+
| VC | 4 | A | 80 |
| VC | 2 | B | 90 |
| VC | 1 | C | 95 |
| ED | 5 | A | 85 |
| ED | 1 | B | 90 |
| ED | 3 | C | 95 |
| PH | 3 | A | 80 |
I want into below format, I want total no of cases per department and every question as column and rate as its value.
| Department | NoOfCases | A | B | C(actual questions as columns) |
+============+===========+====+====+================================+
| VC | 7 | 80 | 90 | 95 |
| ED | 9 | 85 | 90 | 95 |
| PH | 3 | 80 | | |
Can we achieve this?
You can achieve it using a PIVOT with a GROUP BY:
--create table variable to hold sample data
declare #tmp table( Department nvarchar(2),NoOfCases int, Question nvarchar(1), Rate int)
--populate sample data
insert into #tmp select 'VC', 4,'A', 80
insert into #tmp select 'VC', 2,'B', 90
insert into #tmp select 'VC', 1,'C', 95
insert into #tmp select 'ED', 5,'A', 85
insert into #tmp select 'ED', 1,'B', 90
insert into #tmp select 'ED', 3,'C', 95
insert into #tmp select 'PH', 3,'A', 80
select * from #tmp
--pivot with group by
select Department,SUM(piv.NoOfCases) AS NoOfCases,
ISNULL(SUM(A),0) AS A, ISNULL(SUM(B),0) AS B, ISNULL(SUM(C),0) AS C
from
(
--select data
select Department,NoOfCases , Question ,RATE
from #tmp
) src
pivot
(
MAX(RATE)
for Question in ([A], [B], [C])
) piv
GROUP BY Department
This is the output of the command:

How do I identify Interaction in a column and take sum based on values in two other columns?

I have 3 Tables-
Table 1
Customer ID | Date | Score | Score Factor
------------+------------+-------+-------------
100 | 2014-10-10 | 15 | .25
100 | 2014-12-12 | 25 | .35
100 | 2014-08-08 | 35 | .65
100 | 2014-09-08 | 45 | .55
100 | 2014-01-10 | 15 | .25
100 | 2014-12-12 | 75 | .85
100 | 2014-08-08 | 85 | .65
100 | 2015-09-08 | 45 | .55
200 | 2014-10-10 | 45 | .25
200 | 2014-12-12 | 55 | .35
200 | 2014-08-08 | 35 | .65
200 | 2014-09-08 | 45 | .55
200 | 2014-01-10 | 55 | .25
Table 2
Score | Group# | Group Label
-------+--------+-----------+
10 | 1 | Superior |
15 | 1 | Superior |
25 | 1 | Superior |
35 | 2 | Mediocre |
55 | 2 | Mediocre |
65 | 3 | Poor |
75 | 3 | Poor |
85 | 4 | Critical |
Table 3
Interaction | Group label | Group label | Final Score Factor
-------------+--------------+--------------+--------------
INT1 | Superior | Medicocre | .80
INT2 | Superior | Poor | .90
INT3 | Poor | Critical | .95
Based on these tables, here's what I need to find
Identify whether a 'score' for a 'customer ID' belongs to any group for a particular Year
From Table 1 and Table 2-
Customer 100 for year 2014 has scores of-
15, 25 - Group label "Superior"
35 - Group label "Mediocre"
45 - No Group
Once The Groups have been identified, From Table 3, identify if the groups have Interactions and Map Corresponding 'Final Score Factor'.
Customer 100 has score which belong to Group label "Superior" and "Mediocre". Therefore, INT1 exists and Corresponding 'score factor' is .80.
So the expected result table should be as follows-
Customer ID | Date | Score| Score Factor| Group#| Group label| Interaction | Final Score Factor
-------------+------------+------+-------------+--------+-----------+--------------+------------------
100 | 2014-10-10 | 15 | .25 | 1 | Superior | INT1 | .80
100 | 2014-12-12 | 25 | .35 | 1 | Superior | INT1 | .00
100 | 2014-08-08 | 35 | .65 | 2 | Mediocre | INT1 | .00
100 | 2014-08-08 | 45 | .55 | NULL | Null | Null | .55
100 | 2014-12-12 | 75 | .85 | 3 | Poor | INT3 | .95
100 | 2014-08-08 | 85 | .65 | 4 | Critical | INT3 | .00
NOTE:
The 'Final Interaction Score' is accounted only once per interaction. Repeating Values are made equal to .00
If the Score factor does not belong to any Interaction, the same Score is carry forwarded as Final Score Factor (Row 4) in the above example
Now, I have to take the Sum of the 'Final Score Factors' per customer per year.
Therefore from the results table(above),
Resultant Score = .80 + .55 + .95
I don't understand the way you're supposed to map to the Interactions table. I made some table variables for your input as follows:
declare #customers table (id int, thedate date, score int, scorefactor varchar(5) )
insert into #customers values(100,'2014-10-10',15,'.25')
insert into #customers values(100,'2014-12-12',25,'.35')
insert into #customers values(100,'2014-08-08',35,'.65')
insert into #customers values(100,'2014-09-08',45,'.55')
insert into #customers values(100,'2014-01-10',15,'.25')
insert into #customers values(100,'2014-12-12',75,'.85')
insert into #customers values(100,'2014-08-08',85,'.65')
insert into #customers values(100,'2015-09-08',45,'.55')
insert into #customers values(200,'2014-10-10',45,'.25')
insert into #customers values(200,'2014-12-12',55,'.35')
insert into #customers values(200,'2014-08-08',35,'.65')
insert into #customers values(200,'2014-09-08',45,'.55')
insert into #customers values(200,'2014-01-10',55,'.25')
declare #scores table (score int, groupno int, grouplabel varchar(10))
insert into #scores values(10,1,'Superior')
insert into #scores values(15,1,'Superior')
insert into #scores values(25,1,'Superior')
insert into #scores values(35,2,'Mediocre')
insert into #scores values(55,2,'Mediocre')
insert into #scores values(65,3,'Poor')
insert into #scores values(75,3,'Poor')
insert into #scores values(85,4,'Critical')
declare #interactions table(interaction varchar(5), grouplabel1 varchar(10), grouplabel2 varchar(10), finalscorefactor varchar(5))
insert into #interactions values('INT1', 'Superior', 'Mediocre', '.80')
insert into #interactions values('INT2', 'Superior', 'Poor', '.90')
insert into #interactions values('INT3', 'Poor', 'Critical', '.95')
Then, I ran a simple query to match up customer scores to groups for the year 2014:
select distinct c.id, s.grouplabel
from #customers c
inner join #scores s
on c.score = s.score
where thedate < '2015-01-01' and thedate >= '2014-01-01'
The output I get is this:
id | grouplabel
---------------
100 | Critical
100 | Mediocre
100 | Poor
100 | Superior
200 | Mediocre
So I'm getting customer 100 having not just superior and mediocre, but also poor and critical.
Can you explain better how you would match that to the stuff in table 3?

Return Max(Recent_Date) for each month, Duplicate value and inner join issue - SQL

Basically, I want to achieve , for each months, like in this example, from January until March 2013, what is the Max(Most_Recent_Day) for each users.
Example, From January to March, every month in the Database, systems will capture the Most_Recent_Day for each users.
Below are the expected results:
User | Most_Recent_Day
--------------------------------
afolabi.banu | 1/31/2013
afolabi.banu | 2/7/2013
afolabi.banu | 3/21/2013
mario.sapiter | 1/22/2013
mario.sapiter | 2/7/2013
mario.sapiter | 3/11/2013
However, I want to have another DB column as well to be display .Below is the column.
User|Total_Hits | Recent_Month| Most_Recent_Day | Most_Recent_Days_Hits
I tried to use inner join, but the result are not what i expect. I got duplicated user name and duplicated recent day. Basically, I want only to display no duplicated record for the same user name.
Below is the result that I got. Please ignore the recent_month value since it's data from database.
User |Total_Hits | Recent_Month | Most_Recent_Day | Most_Recent_Days_Hits
-------------------------------------------------------------------------------------
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 211 | 13 | 1/31/2013 | 3
afolabi.banu | 223 | 25 | 2/7/2013 | 5
afolabi.banu | 296 | 31 | 3/21/2013 | 1
afolabi.banu | 296 | 31 | 3/21/2013 | 1
mario.sapiter | 95 | 7 | 2/7/2013 | 5
mario.sapiter | 7 | 7 | 3/21/2013 | 1
mario.sapiter | 7 | 37 | 3/22/2013 | 1
mario.sapiter | 249 | 37 | 2/7/2013 | 5
This is my SQL Code
SELECT t.[User],
t.Total_Hits,
t.Recent_Month,
t.Most_Recent_Day,
t.Most_Recent_Day_Hits FROM UserUsageMonthly t
INNER JOIN
(
select
[User]
, max(Most_Recent_Day) as Most_Recent_Day
from UserUsageMonthly (NoLock)
where Application_Name='Daily Production Review' and Site_Collection='wrm13'
and Most_Recent_Day between '1/1/2013' and '3/31/2013'
group by [User], datepart(month,Most_Recent_Day)
) table2
ON
t.[User]=table2.[User]
AND t.Most_Recent_Day = table2.Most_Recent_Day
order by t.[User]
You should add the month value to your SQL SELECT
SELECT
MONTH(t.Most_Recent_Day) as 'MyMonth',
t.[User],
t.Total_Hits,
t.Recent_Month,
t.Most_Recent_Day,
t.Most_Recent_Day_Hits FROM UserUsageMonthly t
Then you can group by the month column
GROUP BY MyMonth