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

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?

Related

How to select timestamp values in PostgreSQL under conditions?

I have a database table 'table1' as follows:
f_key | begin | counts|
1 | 2018-10-04 | 15 |
1 | 2018-10-06 | 20 |
1 | 2018-10-08 | 34 |
1 | 2018-10-09 | 56 |
I have another database table 'table2' as follows:
f_key | p_time | percent|
1 | 2018-10-05 | 80 |
1 | 2018-10-07 | 90 |
1 | 2018-10-08 | 70 |
1 | 2018-10-10 | 60 |
The tables can be joined by the f_key field.
I want to get a combined table as shown below:
If the begin time is earlier than any of the p_time then the p_time value in the combined table would be the same as begin time and the percent value would be 50. (As shown in row 1 in the following table)
If the begin time is later than any of the p_time then the p_time value in the combined table would be the very next available p_time and the percent value would be the corresponding value of the selected p_time.
(As shown in row 2, 3 and 4 in the following table)
row | f_key | begin | counts| p_time | percent|
1 | 1 | 2018-10-04 | 15 | 2018-10-04 | 50 |
2 | 1 | 2018-10-06 | 20 | 2018-10-05 | 80 |
3 | 1 | 2018-10-08 | 34 | 2018-10-07 | 90 |
4 | 1 | 2018-10-09 | 56 | 2018-10-08 | 70 |
You can try to use row_number window function to make row number which is the closest row from table1 by begin.
then use coalesce function to let begin time is earlier than any of the p_time then the p_time value in the combined table would be the same as begin time and the percent value would be 50
PostgreSQL 9.6 Schema Setup:
CREATE TABLE table1(
f_key INT,
begin DATE,
counts INT
);
INSERT INTO table1 VALUES (1,'2018-10-04',15);
INSERT INTO table1 VALUES (1,'2018-10-06',20);
INSERT INTO table1 VALUES (1,'2018-10-08',34);
INSERT INTO table1 VALUES (1,'2018-10-09',56);
CREATE TABLE table2(
f_key INT,
p_time DATE,
percent INT
);
INSERT INTO table2 VALUES (1, '2018-10-05',80);
INSERT INTO table2 VALUES (1, '2018-10-07',90);
INSERT INTO table2 VALUES (1, '2018-10-08',70);
INSERT INTO table2 VALUES (1, '2018-10-10',60);
Query 1:
SELECT ROW_NUMBER() OVER(ORDER BY begin) "row",
t1.f_key,
t1.counts,
coalesce(t1.p_time,t1.begin) p_time,
coalesce(t1.percent,50) percent
FROM (
SELECT ROW_NUMBER() OVER(PARTITION BY t1.begin,t1.f_key order by t2.p_time desc) rn,
t2.p_time,
t2.percent,
t1.counts,
t1.f_key,
t1.begin
FROM table1 t1
LEFT JOIN table2 t2 ON t1.f_key = t2.f_key and t1.begin > t2.p_time
)t1
WHERE rn = 1
Results:
| row | f_key | counts | p_time | percent |
|-----|-------|--------|------------|---------|
| 1 | 1 | 15 | 2018-10-04 | 50 |
| 2 | 1 | 20 | 2018-10-05 | 80 |
| 3 | 1 | 34 | 2018-10-07 | 90 |
| 4 | 1 | 56 | 2018-10-08 | 70 |

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];

Trying to add total for individual for every month/year

" 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

Add extra column in sql to show ratio with previous row

I have a SQL table with a format like this:
SELECT period_id, amount FROM table;
+--------------------+
| period_id | amount |
+-----------+--------+
| 1 | 12 |
| 2 | 11 |
| 3 | 15 |
| 4 | 20 |
| .. | .. |
+-----------+--------+
I'd like to add an extra column (just in my select statement) that calculates the growth ratio with the previous amount, like so:
SELECT period_id, amount, [insert formula here] AS growth FROM table;
+-----------------------------+
| period_id | amount | growth |
+-----------+-----------------+
| 1 | 12 | |
| 2 | 11 | 0.91 | <-- 11/12
| 3 | 15 | 1.36 | <-- 15/11
| 4 | 20 | 1.33 | <-- 20/15
| .. | .. | .. |
+-----------+-----------------+
Just need to work out how to perform the operation with the line before. Not interested in adding to the table. Any help appreciated :)
** also want to point out that period_id is in order but not necessarily increasing incrementally
The window function Lag() would be a good fit here.
You may notice that we use (amount+0.0). This is done just in case AMOUNT is an INT, and NullIf() to avoid the dreaded divide by zero
Declare #YourTable table (period_id int,amount int)
Insert Into #YourTable values
( 1,12),
( 2,11),
( 3,15),
( 4,20)
Select period_id
,amount
,growth = cast((amount+0.0) / NullIf(lag(amount,1) over (Order By Period_ID),0) as decimal(10,2))
From #YourTable
Returns
period_id amount growth
1 12 NULL
2 11 0.92
3 15 1.36
4 20 1.33
If you are using SQL Server 2012+ then go for John Cappelletti answer.
And If you are also less blessed like me then this below code work for you in the 2008 version too.
Declare #YourTable table (period_id int,amount int)
Insert Into #YourTable values
( 1,12),
( 2,11),
( 3,15),
( 4,20)
;WITH CTE AS (
SELECT ROW_NUMBER() OVER (
ORDER BY period_id
) SNO
,period_id
,amount
FROM #YourTable
)
SELECT C1.period_id
,C1.amount
,CASE
WHEN C2.amount IS NOT NULL AND C2.amount<>0
THEN CAST(C1.amount / CAST(C2.amount AS FLOAT) AS DECIMAL(18, 2))
END AS growth
FROM CTE C1
LEFT JOIN CTE C2 ON C1.SNO = C2.SNO + 1
Which works same as LAG.
+-----------+--------+--------+
| period_id | amount | growth |
+-----------+--------+--------+
| 1 | 12 | NULL |
| 2 | 11 | 0.92 |
| 3 | 15 | 1.36 |
| 4 | 20 | 1.33 |
+-----------+--------+--------+

Fixing the payout issue

I am re-posting my original question with edits, as that question was answered and best answer chosen.
Payments comes from our supplier which goes towards the accounts and the reps get paid based on which account got how much.
Customers Table (Usage is kwH)
+----+----------+------------+----------+----------+----------+-------+-------+
| ID | Customer | Account_no | Meter_no | Supplier | Active | Usage | Repid |
+----+----------+------------+----------+----------+----------+-------+-------+
| 1 | Joe | 123 | 111 | NSTAR | active | 20 | 100 |
| 2 | Joe | 123 | 222 | NSTAR | active | 30 | 100 |
| 3 | Joe | 123 | 150 | NSTAR | inactive | 60 | 100 |
| 4 | Sam | 456 | 352 | SEP | active | 50 | 100 |
| 5 | Jill | 789 | 222 | FES | active | 40 | 200 |
| 6 | Mike | 883 | 150 | ABB | inactive | 40 | 200 |
+----+----------+------------+----------+----------+----------+-------+-------+
Payment_Receive (table)
+------------+----------+-------------+-------------+
| Account_no | Supplier | Amount_paid | PaymentDate |
+------------+----------+-------------+-------------+
| 123 | NSTAR | 20 | 2011-11-01 |
| 456 | SEP | 40 | 2011-11-01 |
| 456 | SEP | -40 | 2011-11-01 |
| 456 | SEP | 40 | 2011-11-01 |
| 789 | FES | 50 | 2011-11-01 |
| 883 | ABB | 30 | 2011-11-01 |
+------------+----------+-------------+-------------+
The two tables are used for rep payout. Payment are recieved for each account, they are matched with our customers based on Account_No and Supplier. We do not have control over the payment_table because it comes from outside. This creates certain problems because we can not do one-to-one match between the two tables. Leaving that aside, I would like to have payout calculated for RepID = 100 with certain criteria. This is the output I would like to see for RepId = 100
+------------+----------+-------------+-------------+-------------+
| Account_no | Supplier | Amount_paid | Usage | PaymentDate |
+------------+----------+-------------+-------------+-------------+
| 123 | NSTAR | 20 | 60* | 2011-11-01 |
| 456 | SEP | 40 | 50 | 2011-11-01 |
| 456 | SEP | -40 | 40 | 2011-11-01 |
| 456 | SEP | 40 | 40 | 2011-11-01 |
+------------+----------+-------------+-------------+-------------+
Note here that
Account_no 123 exists thrice in customers table, it must show one time in rep payout
3 amounts were paid to account_no 456, all the three must show in the report
*60 = Notice that there are 2 active records (and one inactive). This could be the sum of the two active. But any other value is acceptable if that makes the query easy (for greater of the two or one, not the other)
Note that Usage column must appear in the output table, This is the column that creates problem for me. If I dont include this everything works fine.
The point with Usage column, if I have two records for same customer having same Account_No and Supplier but different usage, that makes the two records distinct when I include usage column. Therefore distinct does not work to remove this duplicate.
Reports are calculated on Monthly basis
Script for the question
create database testcase
go
use testcase
go
create table customers (
id int not null primary key identity,
customer_name varchar(25),
account_no int,
meter_no int,
supplier varchar(20),
active varchar(20),
usage int,
repid int
)
create table payments_received (
account_no int,
supplier varchar(20),
amount_paid float,
paymentdate smalldatetime
)
insert into customers values('Joe',123, 111,'NSTAR','active',20,100)
insert into customers values('Joe',123, 222,'NSTAR','active',30, 100)
insert into customers values('Joe',123, 150,'NSTAR','inactive',60,100)
insert into customers values('Sam',456, 352,'SEP','active',40,100)
insert into customers values('Jill',789, 222,'FES','active',40,200)
insert into customers values('Mike',883, 150,'ABB','inactive',40,200)
select * from customers
insert into payments_received values(123,'NSTAR',20,'2011-11-01')
insert into payments_received values(456,'SEP',40,'2011-11-01')
insert into payments_received values(456,'SEP',-40,'2011-11-01')
insert into payments_received values(456,'SEP',40,'2011-11-01')
insert into payments_received values(789,'FES',50,'2011-11-01')
insert into payments_received values(883,'ABB',30,'2011-11-01')
select * from payments_received
How about this:
CREATE VIEW v_customers_by_rep
AS
SELECT SUM(USAGE) AS USAGE ,
REPID ,
CAST(account_no AS VARCHAR) + '_' + Supplier AS UniqueId
FROM customers
GROUP BY CAST(account_no AS VARCHAR) + '_' + Supplier ,
REPID
GO
DECLARE
#repid INT
SET #repid = 100
SELECT pr.* ,
u.Usage
FROM payments_received pr INNER JOIN v_customers_by_rep u
ON CAST(pr.account_no AS VARCHAR) + '_' + pr.Supplier = u.UniqueId
WHERE u.repid = #repid
You could also eliminate inactive records in the view if desired.