I need to fix payout issue - example given below (re-edited) - sql

Customer 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 use for rep payout. We do not have control over the payout_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 twice 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
Reports are calculated on Monthly basis
Script for example (Updated with Usage column)
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
Updated: Updated The question and script
Usage been added to Customers table
Usage must appear int the result table
*60 = Notice that there are 2 active records (and one inactive). This could be the sum of the two, the one that is larger. This column is created problem removing duplicates

Two database brand independent options:
option 1:
Select
*
from
Payment_Receive PR
inner join
(select distinct Account_no, Supplier
From Customer where Repid = 100 ) C
on (PR.Account_no = C.Account_no
and PR.Supplier = C.Supplier )
option 2:
Select
*
from
Payment_Receive PR
Where exists
(select *
From Customer C
where
Repid = 100 and
PR.Account_no = C.Account_no and
PR.Supplier = C.Supplier )
with date range:
option 1:
Select
*
from
Payment_Receive PR
inner join
(select distinct Account_no, Supplier
From Customer where Repid = 100 ) C
on (PR.Account_no = C.Account_no
and PR.Supplier = C.Supplier )
where
year(PR.PaymentDate) = 2011 and
month(PR.PaymentDate) = 11
option 2:
Select
*
from
Payment_Receive PR
Where exists
(select *
From Customer C
where
Repid = 100 and
PR.Account_no = C.Account_no and
PR.Supplier = C.Supplier )
and
year(PR.PaymentDate) = 2011 and
month(PR.PaymentDate) = 11

I used a CTE to limit your Customer table, as well as added support for a specific YEAR and MONTH based on your question in a comment.
WITH customersCte AS
(
SELECT id, customer_name, account_no, meter_no, supplier, active, repid
, ROW_NUMBER() OVER (PARTITION BY account_no ORDER BY account_no ASC) AS rowNumber
FROM customers
)
SELECT pr.Account_no, pr.Supplier, pr.Amount_paid, pr.PaymentDate
FROM payments_received AS pr
INNER JOIN customersCte AS c ON pr.account_no = c.account_no
WHERE c.repid = 100
AND c.rowNumber = 1
AND YEAR(pr.PaymentDate) = 2011
AND MONTH(pr.PaymentDate) = 11

Related

eSQL multiple join but with conditions

I've 3 tables as under
MERCHANDISE
+-----------+-----------+---------------+
| MERCH_NUM | MERCH_DIV | MERCH_SUB_DIV |
+-----------+-----------+---------------+
| 1 | car | awd |
| 1 | car | awd |
| 2 | bike | 1kcc |
| 3 | cycle | hybrid |
| 3 | cycle | city |
| 4 | moped | fixie |
+-----------+-----------+---------------+
PRIORITY
+----------+-----------+---------+---------+------------+------------+---------------+
| CUST_NUM | SALES_NUM | DOC_NUM | BALANCE | PRIORITY_1 | PRIORITY_2 | PRIORITY_CODE |
+----------+-----------+---------+---------+------------+------------+---------------+
| 90 | 1000 | 10 | 23 | 1 | 6 | NO |
| 91 | 1001 | 20 | 32 | 3 | 7 | PRI |
| 92 | 1002 | 30 | 11 | 2 | 8 | LATE |
| 93 | 1003 | 40 | 22 | 5 | 9 | 1MON |
+----------+-----------+---------+---------+------------+------------+---------------+
ORDER
+----------+-----------+---------+---------+-----------+-----------+
| CUST_NUM | SALES_NUM | DOC_NUM | COUNTRY | MERCH_NUM | MERCH_DIV |
+----------+-----------+---------+---------+-----------+-----------+
| 90 | 1000 | 10 | INDIA | 1 | car |
| 91 | 1001 | 20 | CHINA | 2 | bike |
| 92 | 1002 | 30 | USA | 3 | cycle |
| 93 | 1003 | 40 | UK | 4 | moped |
+----------+-----------+---------+---------+-----------+-----------+
I want to join the left joined table from the last two tables with the first one such that the MERCH_SUB_DIV 'awd' appears only once for each unique combination of merch_num and merch_div
the code I came up with is as under, but I'm not sure how do I eliminate the duplicate row just for the awd
select
ROW#, MERCH.MERCH_NUMBER, ORDPRI.MERCH_NUMBER, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, ITEM_NUM, RANK, PRIORITY_1
from (
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM, ORD.ITEM_NUM ASC
) AS Row#,
ORD.CUST_NUM, PRI.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from ORDER as ORD
left join PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', ‘INDIA’)
) as ORDPRI
left join MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
You have to use 'DISTINCT' keyword to get unique values, but if your 'Priority table' & 'Order table' contains different values for Same MERCH_NUM then the final result contains the repetation of the 'MERCH_NUM'.
SELECT DISTINCT M.MERCH_NUMBER, O.MERCH_NUMBER, O.CUST_NUM, BALANCE, SALES_NUM,ITEM_NUM,RANK,PRIORITY_1
FROM priority_table P
LEFT JOIN order_table O ON P.CUST_NUM = O.CUST_NUM AND P.SALES_NUM=O.SALES_NUM AND P.DOC_NUM = O.DOC_NUM
LEFT JOIN merchandise_table M ON M.MERCH_NUM = O.MERCH_NUM
A way around can be to add one new Row_Number() in the outermost query having Partition by MERCH_SUB_DIV + all the columns in the final list and then filter final results based on the New Row_Number() . Follows a pseudo code that might help:
select
-- All expected columns in final result except the newRow#
ROW#, MERCH_NUM, CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
select
ROW#,
-- the new row number includes all column you want to show in final result
row_number() over ( PARTITION BY MERCH.MERCH_SUB_DIV ,
MERCH.MERCH_NUM, ORDPRI.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
order by (select 1 )) as newRow# ,
MERCH.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
-- main query goes here
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM --, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM ASC --, ORD.ITEM_NUM
) AS Row#,
ORD.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV as DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from #ORDER as ORD
left join #PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', 'INDIA')
) as ORDPRI
left join #MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
) as T
-- final filter to get distinct values
where newRow# = 1
Sample code here .. Hope this helps!!

How to join two tables in one view?

I am trying to create a view where I can see the items that have been planned to be shipped and have not been shipped, and the items have have been shipped but were not planned to.
In order to do this I have 2 tables with different data in them.
Table SC (actually shipped):
+---------+-----------------+----------------------+-------------+
| item_id | source_location | destination_location | shipped_qty |
+---------+-----------------+----------------------+-------------+
| 001 | California | South_Carolina | 80 |
+---------+-----------------+----------------------+-------------+
| 001 | California | South_Carolina | 0 |
+---------+-----------------+----------------------+-------------+
| 001 | California | Texas | 20 |
+---------+-----------------+----------------------+-------------+
| 003 | Texas | South_Carolina | 200 |
+---------+-----------------+----------------------+-------------+
| 004 | South_Carolina | Texas | 30 |
+---------+-----------------+----------------------+-------------+
| 004 | South_Carolina | Texas | 10 |
+---------+-----------------+----------------------+-------------+
Table SO (plan to ship items):
+---------+-----------------+----------------------+---------------+
| item_id | source_location | destination_location | planned_order |
+---------+-----------------+----------------------+---------------+
| 001 | California | South_Carolina | 100 |
+---------+-----------------+----------------------+---------------+
| 001 | California | South_Carolina | 100 |
+---------+-----------------+----------------------+---------------+
| 001 | California | Texas | 10 |
+---------+-----------------+----------------------+---------------+
| 003 | Texas | South_Carolina | 200 |
+---------+-----------------+----------------------+---------------+
| 004 | South_Carolina | Texas | 300 |
+---------+-----------------+----------------------+---------------+
| 004 | South_Carolina | Texas | 50 |
+---------+-----------------+----------------------+---------------+
So in this case, for example, since the item 001 has three different planned orders from California to South Carolina, I don't want it to show all the three orders in the view, I want it to be only in one row, but sum all the planned orders together, as showed below.
Desired Outcome:
+---------+----------------+-----------------+-------------+-------------+
| item_id | source_loc | destination_loc | shipped_qty | planned_qty |
+---------+----------------+-----------------+-------------+-------------+
| 001 | California | South_Carolina | 80 | 200 |
+---------+----------------+-----------------+-------------+-------------+
| 001 | California | Texas | 20 | 10 |
+---------+----------------+-----------------+-------------+-------------+
| 003 | Texas | South_Carolina | 200 | 200 |
+---------+----------------+-----------------+-------------+-------------+
| 004 | South_Carolina | Texas | 40 | 350 |
+---------+----------------+-----------------+-------------+-------------+
I have tried this so far:
SELECT o.source_location,
o.destination_location,
o.item_id,
o.planned_order,
c.shipped_qty
FROM SO_TRANSFER o, SC_TRANSFER c
But this hasn't worked since the shipped_qty does not match the item and this code also does not add the orders together.
By the way, I am using Microsoft SQL Server 2012.
Thank you!
I think you want:
select coalesce(s.item_id, p.item_id) as item_id,
coalesce(s.source_location, p.source_location) as source_location,
coalesce(s.destination_location, p.destination_location) as destination_location,
coalesce(s.shipped_qty, 0) as shipped_qty,
coalesce(planned_qty, 0) as planned_qty
from (select item_id, source_location, destination_location, sum(shipped_qty) as shipped_qty
from sc
group by item_id, source_location, destination_location
) s full join
(select item_id, source_location, destination_location, sum(planned_qty) as planned_qty
from so
group by item_id, source_location, destination_location
) p
on s.item_id = p.item_id and
s.source_location = p.source_location and
s.destination_location = p.destination_location;
You can try this:
SELECT A.item_id,
A.source_location AS source_loc,
A.destination_location AS destination_loc,
A.shipped_qty,
B.planned_order
FROM
(SELECT item_id,source_location,destination_location,SUM(shipped_qty)
AS shipped_qty
FROM SC GROUP BY item_id,source_location,destination_location) A,
(SELECT item_id,source_location,destination_location,SUM(planned_order)
AS planned_order
FROM SO GROUP BY item_id,source_location,destination_location) B
WHERE A.item_id = B.item_id AND
A.source_location= B.source_location AND
A.destination_location= B.destination_location
EDIT: I just realize my answer is similar to Gordon Linoff's answer, and his answer got more feature such as handling data that exists in one table only using COALESCE in T-SQL and FULL JOIN property. Since I worked 1 hour for this answer, so I will just leave it here.
The point is you should SUM(quantity) from each table first, then you can easy JOIN 2 table with condition:
ON so.item_id = sc.item_id AND so.source_loc = sc.source_loc AND so.destination_loc = sc.destination_loc
The following query will do what you are looking for
Create table #SC(
item_id varchar(50),
source_location varchar(max),
Destination_location varchar(max),
Shipped_qty int)
insert into #SC values('001','california','sourth_carolian',80)
insert into #SC values('001','california','sourth_carolian',0)
insert into #SC values('001','california','Texas',20)
insert into #SC values('003','Texas','sourth_carolian',200)
insert into #SC values('004','sourth_carolian','Texas',30)
insert into #SC values('004','sourth_carolian','Texas',10)
--select * from #SC
Create table #SO(
item_id varchar(50),
source_location varchar(max),
Destination_location varchar(max),
Planned_order int)
insert into #SO values('001','california','sourth_carolian',100)
insert into #SO values('001','california','sourth_carolian',100)
insert into #SO values('001','california','Texas',10)
insert into #SO values('003','Texas','sourth_carolian',200)
insert into #SO values('004','sourth_carolian','Texas',300)
insert into #SO values('004','sourth_carolian','Texas',50)
--select * from #SO
select C.item_id,C.source_location,C.Destination_location, sum(C.Shipped_qty) as Shipped_qty, po.planned_order from #SC C
outer apply
(select sum(Planned_order) as planned_order from #SO
where source_location+Destination_location=C.source_location+C.Destination_location
group by item_id,source_location,Destination_location ) as PO
group by C.item_id,C.source_location,C.Destination_location,po.planned_order
You can create a SELECT statement, and use that as a table in the FROM clause:
SELECT o.source_location,
o.destination_location,
o.item_id,
o.planned_order,
c.shipped_qty_sum
FROM SO_TRANSFER o
INNER JOIN (SELECT SUM(shipped_qty) AS shipped_qty_sum,
source_location,
item_id
FROM SC_TRANSFER
GROUP BY source_location, item_id) c
ON o.item_id = c.item_id AND o.source_location = c.source_location

Using CASE in WHERE clause

I have 2 tables that needs to be joined based on couple of parameters. One of the parameters is year. One table contains the current year but another year doesn't contain current year, so it must use the latest year and matched with other parameters.
Example
Product
-------------------------------------------------------------------------------
| product_id | category_id | sub_category_id | product_year | amount |
-------------------------------------------------------------------------------
| 504 | I | U | 2020 | 400 |
| 510 | I | U | 2019 | 100 |
| 528 | I | U | 2019 | 150 |
| 540 | I | U | 2018 | 1000 |
Discount
-----------------------------------------------------------------------------
| discount_year | category_id | sub_category_id | discount |
-----------------------------------------------------------------------------
| 2018 | I | U | 0.15 |
| 2017 | I | U | 0.35 |
| 2016 | I | U | 0.50 |
Output
-----------------------------------------------------------------------------
| product_id | category_id | sub_category_id | product_year | discount_year |
-----------------------------------------------------------------------------
| 504 | I | U | 2020 | 2018 |
| 510 | I | U | 2019 | 2018 |
| 528 | I | U | 2019 | 2018 |
| 540 | I | U | 2018 | 2017 |
The discount is always gotten from one year behind but if those rates aren't available, then it would keep going back a year until available.
I have tried the following:
SELECT
product_year, a.product_id, a.category_id, a.sub_category_id,
discount_year, amount, discount
FROM
Product a
INNER JOIN
Discount b ON a.category_id = b.category_id
AND a.sub_category_id = b.sub_category_id
AND product_ year = CASE
WHEN discount_year + 1 = product_year
THEN discount_year + 1
WHEN discount_year + 2 = product_year
THEN discount_year + 2
WHEN discount_year + 3 = product_year
THEN discount_year + 3
END
WHERE
product = 540
This return the following output:
--------------------------------------------------------------------------------------------------
| product_year | product_id | category_id | sub_category_id | discount_year | amount | discount |
--------------------------------------------------------------------------------------------------
| 2016 | 540 | I | U | 2017 | 1000 | 0.50 |
| 2017 | 540 | I | U | 2017 | 1000 | 0.35 |
Any help will be appreciated.
You can use OUTER APPLY and a subquery. In the subquery select the row with the maximum discount_year, that is less the product_year using TOP and ORDER BY.
SELECT p.product_year,
p.product_id,
p.category_id,
p.sub_category_id,
d.discount_year,
p.amount,
d.discount
FROM product p
OUTER APPLY (SELECT TOP 1
*
FROM discount d
WHERE d.category_id = p.category_id
AND d.sub_category_id = p.sub_category_id
AND d.discount_year < p.product_year
ORDER BY d.discount_year DESC) d;
instead of a CASE expression you can use a sub-query to select the TOP 1 related
discount_year that is less than your product_year, ORDER BY discount_year ASC.
Create a product to discount mapping using a CTE first. This contains the discount year pulled from discount table for every product year in the product table and corresponding product_id. Following this, you can easily join with relevant tables to get results and eliminate any nulls as needed
Simplified query.
;WITH disc_prod_mapper
AS
(
SELECT product_id, product_year,(SELECT MAX(discount_year) FROM #Discount b WHERE discount_year < product_year AND a.category_id = b.category_id AND a.sub_category_id = b.sub_category_id ) AS discount_year
FROM Product a
)
SELECT a.product_year, c.discount_year, a.amount, c.discount
FROM Product a
LEFT JOIN disc_prod_mapper b ON a.product_id = b.product_id
LEFT JOIN Discount c ON b.discount_year = c.discount_year

How can I select from one table where the ID exists in one of two tables, but not in either of other two tables

This sounds confusing, but the idea is quite simple.
I want to get a list of products that have default rates, but a given 'Agent' doesn't have rates for. To do that, I need to select from the below table
t_Products
|-ProductID-|--Product-|
| 100 | Product1 |
| 101 | Product2 |
| 102 | product3 |
| 103 | product4 |
Where the ID exists in either t_Annual_DefaultCost or t_Daily_DefaultCost
t_Annual_DefaultCost
|-DefaultID-|-ProductID-|--Cost-|
| 100 | 100 | 24.00 |
| 101 | 101 | 26.00 |
t_Daily_DefaultCost
|-DefaultID-|-ProductID-|--Cost-|-Days-|
| 100 | 100 | 24.00 | 1 |
| 101 | 100 | 26.00 | 2 |
| 102 | 102 | 22.50 | 2 |
| 103 | 102 | 97.50 | 8 |
But it cannot exist in either t_Annual_AgentCost or t_Daily_AgentCost for the given Agent ID
t_Annual_AgentCost
|---CostID--|-ProductID-|-AgentID-|--Cost-|
| 100 | 100 | 10001 | 24.00 |
| 101 | 100 | 10001 | 20.00 |
t_Daily_AgentCost
|---CostID--|-ProductID-|-AgentID-|--Cost-|-Days-|
| 100 | 100 | 10001 | 24.00 | 1 |
| 102 | 102 | 10002 | 35.00 | 2 |
so for AgentID 10001 the end result should be
|-ProductID-|--Product-|
| 101 | product2 |
| 102 | product3 |
and for AgentID 10002 the end result should be
|-ProductID-|--Product-|
| 100 | product1 |
| 101 | product2 |
I'm currently using the below code to get a list of products that have default rates.
But I can't work out how to remove/not get the ones also in the AgentCost tables.
Select
distinct a.*
from
t_Products as a
inner join
(
select
DefaultID ,ProductID
from
t_Daily_DefalutCost
union
select
DefaultID , ProductID
from
t_Annual_DefaultCost
)
as b on a.ProductID = b.ProductID
If you want to do one Agent at a time, then this is how I would do it:
SELECT
a.*
FROM
t_Products As a
WHERE
( EXISTS( SELECT * FROM t_Daily_DefaultCost As d WHERE d.ProductID = a.ProductID )
OR EXISTS( SELECT * FROM t_Annual_DefaultCost As d WHERE d.ProductID = a.ProductID )
)
AND NOT
( EXISTS( SELECT * FROM t_Daily_AgentCost As d
WHERE d.ProductID = a.ProductID
AND d.AgentID = #SpecifedAgentID )
OR EXISTS( SELECT * FROM t_Annual_AgentCost As d
WHERE d.ProductID = a.ProductID
AND d.AgentID = #SpecifedAgentID )
)
The OR EXISTSs here work pretty much the same as UNION ALL SELECTs would .
I'd use this sort of approach.
select yourfields
from yourtables
where id in
(
(select id
from onetable
union
select id
from anothertable)
except
(select id
from yetanothertable
union
select id
from thefinaltable)
)
You can fill in the actual table names.

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.