find total amount of a customer in SQL - mysql

i'm trying to find out the total amount of a particular customer in an inventory database.
the tables are :
customer, tax, invoice, line_no, branch, items, employee
i was able to calculate the total but i get multiple amounts as it calculates the amount for each tax rate in the database. i'm trying to restrict the amount depending on the branch issues it. i hope i made it clear, here is the query:
SELECT ROUND((SUM((LINE_NO.RETAIL_PRICE - LINE_NO.DISCOUNT)* LINE_NO.DEL_QTY)* (TAX.TAX_RATE))+
SUM((LINE_NO.RETAIL_PRICE - LINE_NO.DISCOUNT)* LINE_NO.DEL_QTY),2)
AS "TOTAL PAYMENT"
FROM LINE_NO, TAX, BRANCH
WHERE LINE_NO.INVOICE_INVOICE_NO IN (SELECT INVOICE.INVOICE_NO from INVOICE
WHERE(INVOICE.CUSTOMER_CUST_NO IN (SELECT CUST_NO from CUSTOMER where CUSTOMER.FNAME='JIM' )))
AND TAX.CITY = BRANCH.CITY
GROUP BY TAX.TAX_RATE;

GROUP BY should not operate on TAX_RATE here to avoid calculate total amount for each group (TAX_RATE).
SELECT ROUND((SUM((LINE_NO.RETAIL_PRICE - LINE_NO.DISCOUNT)* LINE_NO.DEL_QTY)* (TAX.TAX_RATE))+
SUM((LINE_NO.RETAIL_PRICE - LINE_NO.DISCOUNT)* LINE_NO.DEL_QTY),2)
AS "TOTAL PAYMENT"
FROM LINE_NO, TAX, BRANCH
WHERE LINE_NO.INVOICE_INVOICE_NO IN (SELECT INVOICE.INVOICE_NO from INVOICE
WHERE(INVOICE.CUSTOMER_CUST_NO IN (SELECT CUST_NO from CUSTOMER where CUSTOMER.FNAME='JIM' )))
AND TAX.CITY = BRANCH.CITY;

exactly. yes the rate can be retrieved from the branch location, which can be tracked by the Invoice number. so i added another query after:
AND TAX.CITY = BRANCH.CITY
which helped to determine the tax rate i'm looking for and got it working, thanks anyways

Related

SSRS Sorting by Year group total

I have a tablix that has Customer as the row group and Month and Year as Column Groups. Sales amount is in the data area. I would like to sort the customers in descending order by the Year total sales.
I tried the following (psuedo code)
SELECT
Period (a CONCAT of YEAR(date) and MONTH(Date),
SUM(Amount),
Company
FROM [tables]
Group by Period and Company
ORDER BY Sum(Amount) Desc
I did it this way thinking that if I sorted in the query it would come through in the order I want, but obviously it's showing the customer with the highest single month sales first, not the highest year.
Thinking more about it, if I want the report to be able to span multiple years, then I have to figure out which Year to total on, but I'd be happy to restrict the report to a single Year (identified by a parameter).
When I try to sort the tablix or customer group on Sum(Fields!Amount.value, "xYear") I get the error that aggregates can include groups.
I switched from Tablix to Matrix and now sorting the Customer Group by SUM(Fields!Amount.Value) works.... kind of.
It sorts by the grand total as opposed to a given year, but I can live with that for now. Maybe I'll add a parameter that defaults to the current year and try to figure out how to use that to enforce the sort. I'm thinking I may have to get the total YTD sales by customer in a separate dataset (that doesn't display in the report).
You could do it two ways.. (not tested... it's midnight here...) assuming you have a parameter to select the sort year and the Period is a date - adjust to suit...
You could sort by an expression something like
=SUM(
IIF(
YEAR(Fields!Period.Value) = Parameters!pSortYear.Value,
Fields!Amount.Value,
0),
"myDataSetName")
NOte The dataset name must match your dataset name exactly (case sensitive) and be enclosed in double quotes.
Or.. what I normally do is do it in SQL
SELECT Period, Company, SUM(Amount) AS Amount
INTO #data
FROM myTable
GROUP BY Period, Company
SELECT d.*, s.SortOrder
FROM #data d
JOIN (
SELECT Company, ROW_NUMBER() OVER(ORDER BY Amount DESC) as SortOrder
FROM #data
WHERE Period = #pSortYear
) s on d.Company = s.Company
Then in your report you can simply sort by SortOrder
This is done off he top of my head so there could be some basic errors but hopefully close enough for you to follow.

I am trying to find out fastest growing account (in terms of balances)

The slope of line on X-axis is days and Y-axis is balance.
I need to find the steepest slope.
I am thinking to try
SELECT (MAX(balance)-MIN(balance)) / DATEDIFF(MAX(date),MIN(date)) AS time
FROM account
GROUP BY account_id
Does this work?
Anyone having simple ways to solve it?
Thanks in advance :)
I don't think your answer will work.
It will get the max date, max balance, and min date, and min balance for a given account. Your max date will be the most recent date, but max balance may be from months ago. So your growth over time gets messed up. Your balance may be $1 on day 1, $1M on day 2, and $2 on day 1000. Your math will show $1M - $1 over 1000 days. I think you want it to show $2 - $1 over 1000 days.
I prefer the following. You may have to check it for syntax but the logic is there. Basically you partition over rows to order all the balances for a given account in order of the date of the balance. The most recent balance for each account is ranked 1. Your WHERE clause then makes your table only contain the most recent balances for each account. You then join that to a table that does the same thing, except its all the old balances. So now you have the oldest and newest balance for each account.
Then you can select to get the newest less the oldest balance, and divide that by the number of days between those balance. The top is the growth, the denominator is the time. The largest factorial that pops out will be your answer - the growth over time.
SELECT
mostRecentBalances.balance as mostRecentbalance,
mostRecentBalances.date as recentDate,
oldestBalances.balance as oldestBalance,
oldestBalances.date as OldestDate,
(mostRecentBalances.balance - oldestBalances.balance) / DATEDIFF(MAX(mostRecentBalances.date),MIN(oldestBalances.date)) as growthFactor
FROM
(SELECT
balance,
(ROW_NUMBER() over (PARTITION BY balance GROUP BY account_id ORDER BY date DESC) as RowNumber
WHERE
RowNumber = 1 ) mostRecentBalances
INNER JOIN
(SELECT
balance,
(ROW_NUMBER() over (PARTITION BY balance GROUP BY account_id ORDER BY date ASC) as RowNumber
WHERE
RowNumber = 1 ) OldestBalances
on mostRecentBalances.account_id = oldestBalances.account_id
ORDER BY
growthFactor DESC

SQL Adding and Subtracting Data From Two Different Tables

I am new in SQL, and this is my first SQL program ever my life. I want to make a program that has the following:
A table that has the record of number of loads that a customer delivered in a week, the rate(fee) for each load to deliver, the dispatch fee.
Another table that holds expenses, such us Fuel, Insurance, Trailer rent, etc.
I need to get the total sum of all expenses of a customer, and sum of all rates (earned money for each load), and then subtract the total expenses from the total net pays for each customer.
Note:
QuickPay= Rate*0.05
NetPay=Rate-(DispatchFee+QuickPay),
TotalExpenses= Fuel+Advance+Insurance+Trailer
FinalPay=NetPay-TotalExpenses
I have created one query for each table, to make the calculation, but I need to combine all in one query. Here is the code for the queries:
Query For TblLInfo
SELECT CustName, sum(Rate) AS RateFee, sum(Disp_Fee) AS DispFee, sum(Rate*0.05) AS QuickPay, sum((Rate)-((Rate*0.05)+(Disp_Fee))) AS NetPay
FROM TblLInfo
GROUP BY CustName;
Query For TblExp
SELECT CustName, sum(Fuel) AS FuelFee, sum(Advance) AS AdvanceFee, sum(Insurance) AS InsuranceFee, sum(Trailer) AS TrailerFee,
sum((Advance)+(Insurance)+(Trailer)+(Fuel)) AS TotalExp
FROM TblExp
GROUP BY CustName;
When I tried to combine them, the result is 9 (3*3), records as I expected only 3 records.
[TblLInfo,(Table Load Info), For collecting weekly loads transported one customer][1]
[TblExp (Table Expenses), For collecting weekly expenses for each customer][2]
[Query For TblLInfo, to get the sum of all loads carried specific customer and subtract the dispatch fee, so we can get the net pay][3]
[Query for TblExp, to get total expenses for specific customer][4]
![enter image description here][1]
![enter image description here][2]
SELECT a.CustName,a.NetPay,b.TotalExp,(b.TotalExp-a.NetPay) AS overall_profit
FROM
(SELECT CustName, sum(Rate) AS RateFee, sum(Disp_Fee) AS DispFee, sum(Rate*0.05) AS QuickPay, sum((Rate)-((Rate*0.05)+(Disp_Fee))) AS NetPay FROM TblLInfo GROUP BY CustName) a
INNER JOIN
(SELECT CustName, sum(Fuel) AS FuelFee, sum(Advance) AS AdvanceFee, sum(Insurance) AS InsuranceFee, sum(Trailer) AS TrailerFee, sum((Advance)+(Insurance)+(Trailer)+(Fuel)) AS TotalExp FROM TblExp GROUP BY CustName)b

Trying to think of the best database schema for storing dates ranges that will require joins

(Table names in quotes)
Let's say there are "users" that try to sells "products". They earn a commission on all "product_sales" (id, product_id, user_id, total, sale_date). I want to somehow store their commission rate based on certain dates. For example, a user will earn 1% from 2015-01-01 to 2015-01-15, 2% from 2015-01-16 to 2015-01-28, and 3% from 2015-01-29 onwards.
I want to run a query that calculates the total commissions for a user in January.
I want to run a query that calculates daily earnings in January.
How do I store the commission rates? One idea was having a table "user_commissions" that has (id, user_id, commission_rate, from_date, to_date). It would be easy to calculate the rate for (1) if commissions stayed the same, in which case I'd do this:
SELECT (sum(total) * 0.01) as total_commissions FROM product_sales WHERE user_id = 5 and sale_date between '2015-01-01' and '2015-01-31'
But with commission rates variable this is more complex. I need to somehow join the commissions table on each sale to get the right totals.
Another question would be:
How do I store the users' current commission rate that doesn't have an expiration date and include that in the reports? In my example, "3% from 2015-01-29 onwards". This has no end date.
Your table structure is a very reasonable structure and often used for slowly changing dimensions. Storing the effective and end dates in the structure is important for efficiency.
One way to store to_date for the most recent commission is to use NULL. This allows you to do:
select *
from commissions
where to_date is null
to get the most recent record.
However, a better way is to use some far distant date, such as '9999-12-12'. This allows you get the most recent commission using:
where curdate() between from_date and to_date
This is an expression that can also make use of an index on from_date, to_date.
Honestly, I would store user commission percentages and the effective dates of those commissions in one table.
TABLE: COMMISSION
user_id, date_effective, commission
In the other table I would store sales data. With each sale, I would keep the commission the salesperson got on the sale. (Added bonus, you can change the commission on any sale, like an override of sorts.)
TABLE: SALE
sale_id, sale_date, user_id, sale_amount, commission
When you create the row in your program, you can grab the correct commission rate using the following query:
SELECT commission from commission WHERE user_id=[user's id] AND date_effective<=[sale date, today] ORDER BY date_effective ASC;
MySQL Left Joins, and SQL in general, can get really tricky when trying to join on dates that don't exactly match up. (Looking back, basically.) I am struggling with the same problem right now without the luxury of the solution I just suggested.
(This whole post is based on the assumption that you aren't going to be directly interacting with this database through a DBMS but instead through an application.)

Sales and refunds table

I have a "transactions" MySQL table on which I record all sales and refunds for my products. Each record thus either represents a sale or a refund (indicated by a flag), the transaction id, the transaction date and the value of the transaction. In case of refunds there is also a refund_id which indicates for which transaction id this refund is for.
Can I, using one query only, calculate how many sales were made in a certain time period (a sale is considered if the refund value is less than the sale value) and the overall amount earned (ie sales value minus refund value).
Notes:
1. There can be at most one refund for every sale.
2. In case of refunds the date to keep in mind is not the date when the refund was done (ie what is recorded in the DB for a particula refund), but when the original sale was done
SELECT SUM(numberofsales) as numberofsales,SUM(salevalue)
FROM (
--handle sales with refunds
SELECT count(sales) as numberofsales, sum(sales.value-refunds.value) as salevalue
FROM Transactions sales
LEFT JOIN transactions refunds ON sales.transid=refunds.refundid
WHERE refunds.refundid IS NOT NULL
AND sales.value-refund.value>0
AND sales.date>#begindate
AND sales.date<#enddate
AND sales.refund_flag='s'
UNION
--handle sales without refunds
SELECT count(sales) as numberofsales, sum(sales.value) as salevalue
FROM Transactions sales
LEFT JOIN transactions refunds ON sales.transid=refunds.refundid
WHERE refunds.refundid IS NULL
AND sales.date>#begindate
AND sales.date<#enddate
AND sales.refund_flag='s')
This is a first pass with the major charachteristics of the solution.
It's using SQL Server syntax, I'm not sure of the differences between sql server and mysql.
As per michael667's answer above, you can see the self join to get the refunds for each sale.
I dont think the group by is required.
This solution does not attempt to ensure there is only one refund for each sale, and indeed if there is more than one, it will affect the corrrectness of this solution.
This can be done using a self join in conjunction with group by.