I've trying to convert this same into a "Gross Profit" type report and am running into an issue.
select
CONVERT(VARCHAR(12), ih.invoice_date,110) as invoice_date,
oh.order_no,
bosr.salesrep_name,
bosr.salesrep_id,
oh.location_id,
oh.taker,
oh.customer_id,
Replace(oh.ship2_name, ',', ' ') as Ship_to_name,
bosr.supplier_id,
Replace(bosr.supplier_name, ',', ' ') as Supplier_name,
Cast((dc.dealer_commission_amt_due) as DECIMAL (19,2)) as "Gross Profit"
from oe_hdr oh
inner join anspin_view_booked_orders_ship_to_rep bosr
on oh.order_no = bosr.order_no
inner join oe_line ol
on oh.order_no = ol.order_no
inner join invoice_hdr ih
on oh.order_no = ih.order_no
inner join dealer_commission dc
on ih.invoice_no = dc.invoice_no
where
ih.invoice_date >= '2014-07-01' and
ih.invoice_date < '2014-08-01' and
ol.qty_ordered > '0' and
bosr.source_code_no <> '706' and
bosr.source_code_no <> '709'
group by
CONVERT(VARCHAR(12), ih.invoice_date, 110),
oh.order_no,
bosr.salesrep_name,
bosr.salesrep_id,
oh.location_id,
oh.customer_id,
oh.taker,
oh.ship2_name,
bosr.supplier_id,
bosr.supplier_name,
dc.dealer_commission_amt_due
order by invoice_date;
This worked great and the "Gross Profit" column is showing the correct values in the date range I want...now if I were to remove the "dc.dealer_commission_amt_due" from the group by, and then make this change:
Cast(sum(dc.dealer_commission_amt_due) as DECIMAL (19,2)) as "Gross Profit"
I get amounts in SOME (Not all! Which is weird since some are correct) of the invoice numbers as 2-4+ times their original value.
Example Between the two:
invoice_date order_no salesrep_name salesrep_id location_id taker customer_id Ship_to_name supplier_id Supplier_name Gross Profit
07-10-2014 X NAME ID 60 NAME X Customer INC 123452 supplier INC. 4800.00
Non-Sum:
invoice_date order_no salesrep_name salesrep_id location_id taker customer_id Ship_to_name supplier_id Supplier_name Gross Profit
07-10-2014 X NAME ID 60 NAME X Customer INC 123452 supplier INC. 750.00
invoice_date order_no salesrep_name salesrep_id location_id taker customer_id Ship_to_name supplier_id Supplier_name Gross Profit
07-10-2014 X NAME ID 60 NAME X Customer INC 123452 supplier INC. 450.00
From what I've read this has to do with the joins...is this correct?
These two queries are not the same:
SELECT Cast(( dc.dealer_commission_amt_due ) AS DECIMAL (19, 2)) AS "Gross Profit"
FROM dealer_commission dc
GROUP BY dc.dealer_commission_amt_due
SELECT Cast(( SUM(dc.dealer_commission_amt_due) ) AS DECIMAL (19, 2)) AS "Gross Profit"
FROM dealer_commission dc
Adding additional columns in your GROUP BY clause will return more rows in the result, but it should not effect the sum. Removing a column in the GROUP BY will return less rows and again should not effect the sum.
The only part of the query that can effect the sum is which rows are matched.
Also, keep in mind the order of operations of a query:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
Do you need an aggregation?
select
CONVERT(VARCHAR(12), ih.invoice_date,110) as invoice_date,
oh.order_no,
bosr.salesrep_name,
bosr.salesrep_id,
oh.location_id,
oh.taker,
oh.customer_id,
Replace(oh.ship2_name, ',', ' ') as Ship_to_name,
bosr.supplier_id,
Replace(bosr.supplier_name, ',', ' ') as Supplier_name,
SUM(Cast((dc.dealer_commission_amt_due) as DECIMAL (19,2))) as "Gross Profit" --<<AGGREGATION ADDED
from oe_hdr oh
inner join anspin_view_booked_orders_ship_to_rep bosr
on oh.order_no = bosr.order_no
inner join oe_line ol
on oh.order_no = ol.order_no
inner join invoice_hdr ih
on oh.order_no = ih.order_no
inner join dealer_commission dc
on ih.invoice_no = dc.invoice_no
where
ih.invoice_date >= '2014-07-01' and
ih.invoice_date < '2014-08-01' and
ol.qty_ordered > '0' and
bosr.source_code_no <> '706' and
bosr.source_code_no <> '709'
group by
CONVERT(VARCHAR(12), ih.invoice_date, 110),
oh.order_no,
bosr.salesrep_name,
bosr.salesrep_id,
oh.location_id,
oh.customer_id,
oh.taker,
oh.ship2_name,
bosr.supplier_id,
bosr.supplier_name
order by invoice_date;
Ended up having to pay for the software company to write a query since they have the "encyclopedia" on linking the different tables together.
I was able to get 50% there by getting rid of the multiplication on my own, but only 50% of the order types were showing up...I gave up and now have a working query that I can compare against.
Thanks for all your help and suggestions!
Related
Here for database schema
The Case Problem:
What was the total number of purchases of dairy products for each month of 2020 (i.e., the total_sales)?
What was the total share of dairy products (out of all products purchased) for each month of 2020 (i.e., the market_share)?
For each month of 2020, what was the percentage increase or decrease in total monthly dairy purchases compared to the same month in 2019 (i.e., the year_change)?
As a result, it interested in these three categories (which they treat as dairy): ‘whole milk’, 'yogurt' and 'domestic eggs'.
The instruction:
Order your query by month in ascending order. Both month and total_sales should be expressed as integers, and market_share and year_change should be percentages rounded to two decimal places (e.g., 27.95% becomes 27.95).
Your query will need to return a table that resembles the following, including the same column names.
Here for the code:
with purchases_2019 as (SELECT p1.month as month,COUNT(p1.purchase_id) as count_2
FROM purchases_2019 as p1
LEFT JOIN categories as cat ON p1.purchase_id=cat.purchase_id
WHERE cat.category IN ('whole milk', 'yogurt' ,'domestic eggs')
GROUP BY p1.month
ORDER BY p1.month ASC),
purchases_2020 as ( SELECT to_char(CAST(p2.fulldate AS DATE),'MM')::int as month,
COUNT(p2.purchaseid) as total_sales,
ROUND((COUNT(p2.purchaseid)*100::numeric/18277)::numeric,2) as market_share
FROM purchases_2020 as p2
LEFT JOIN categories as cat ON p2.purchaseid=cat.purchase_id
WHERE cat.category IN ('whole milk', 'yogurt' ,'domestic eggs')
GROUP BY month
ORDER BY month ASC)
SELECT t2.month,t2.total_sales,t2.market_share,
ROUND(((t2.total_sales-t1.count_2)*100::numeric/t1.count_2) ,2) as year_change
FROM purchases_2020 as t2
INNER JOIN purchases_2019 as t1 ON t2.month=t1.month
The result is obtained:
But it's still wrong answer. I don't have any idea. Can you give me some enlightenment? Thank You
with p as
(select
extract(month from to_date(b.full_date, 'YYYY/MM/DD')) as "month",
sum(case when c.category in ('whole milk', 'yogurt', 'domestic eggs') then 1 else 0 end) as "old_sales"
from purchases_2019 b left join categories c
on b.purchase_id = c.purchase_id
group by 1
order by 1),
temp as
(select
extract(month from to_date(a.fulldate,'YYYY/MM/DD')) as "month",
sum(case when c.category in ('whole milk', 'yogurt', 'domestic eggs') then 1 else 0 end) as "total_sales",
round(100 * sum(case when c.category in ('whole milk', 'yogurt', 'domestic eggs') then 1 else 0 end)::numeric
/ count(a.purchaseid),2) as "market_share"
from
purchases_2020 a left join categories c
on a.purchaseid = c.purchase_id
group by 1
order by 1)
select
temp.month, total_sales, market_share,
round(100 * (total_sales - old_sales)::numeric / old_sales, 2) as "year_change"
from temp left join p on temp.month = p.month;
Why 18277?
This part:
ROUND((COUNT(p2.purchaseid)*100::numeric/18277)::numeric,2) as market_share
Could there be an error in the market_share calculation?
I think in this code, only 3 categories are calculated, but market share should not be all sales/3 category sales?
Just an idea.
The sales director would like to reward the employees with net sales over $150,000 for the years 2015 and 2016 combined. The Sales Manager would like the resulting query to display the following columns: Employee ID, Employee Name (First and Last as one field), Total Net Sales per employee. (Both years should be combined into one number.)
Sort largest to smallest.
We cannot figure out how to combine the revenues by the employees.
select o.EmpID, EmpFName + ' ' + EmpLastName as "Employee Name"
, sum((salesunitprice*quantitysold)-((salesunitprice*quantitysold)*ItemDiscount)) as "Net Sales"
from EMPLOYEE e
inner join ORDERS o on e.EmpID = o.EmpID
inner join SALES_INVOICE si on o.OrderID = si.OrderID
inner join SALES_INVOICE_DETAIL sd on si.SalesInvoiceID = sd.SalesInvoiceID
group by o.EmpID, EmpFName + ' ' + EmpLastName, OrderDate
having OrderDate between '2015-01-01' and '2016-12-31'
order by [Employee Name]
I expected the output to be the total per employee, but it is broken out by individual order dates instead of summing the total net sales per employee.
Remove OrderDate from the GROUP BY:
select o.EmpID, EmpFName + ' ' + EmpLastName as "Employee Name",
sum(salesunitprice * quantitysold * (1 - discount)) as "Net Sales"
from EMPLOYEE e join
ORDERS o
on e.EmpID = o.EmpID join
SALES_INVOICE si
on o.OrderID = si.OrderID join
SALES_INVOICE_DETAIL sd
on si.SalesInvoiceID = sd.SalesInvoiceID
where o.OrderDate >= '2015-01-01' and
o.OrderDate < '2017-01-01'
group by o.EmpID, EmpFName + ' ' + EmpLastName
having sum(salesunitprice * quantitysold * (1 - discount)) >= 150000
order by [Employee Name]
Notes:
You want to do the date filtering before the aggregation.
BETWEEN doesn't work with datetimes. The formulation with >= and < works with both dates and datetimes.
I have simplified the arithmetic to calculate net sales.
The important part is removing the extra key in the GROUP BY.
And you want a having clause to filter the net sales.
I'm Trying to Get the date , Discount , Total , Net Total ... ordered by date , the discount is showing the real amount but when I select multiple dates the total will be summed in those dates I've selected and it will be ordered by date
DECLARE #pR FLOAT = (SELECT SUM(CAST(Price AS FLOAT)) AS Price
FROM Orders WHERE isPaid = 1
AND PaidDate BETWEEN '8/17/2015' AND '8/18/2015' ) ;
SELECT Orders.PaidDate
, #pR AS Total
,sum(theorderids.Discount) As Discount
,(#pR - sum(theorderids.Discount)) AS [Net Total]
From
(SELECT OrderId, PaidDate
FROM Orders
WHERE Orders.PaidDate BETWEEN '8/17/2015' AND'8/18/2015'
GROUP BY Orders.OrderId, Orders.PaidDate) AS Orders
INNER JOIN theorderids ON Orders.OrderId = theorderids.ID
GROUP BY Orders.PaidDate ;
Example Data :
Row 1
"PaidDate": "17-08-2015",
"Total": 7388.0,
"Discount": 38.0,
"NetTotal": 7363.0
Row 2
"PaidDate": "18-08-2015",
"Total": 7388.0,
"Discount": 2.0,
"NetTotal": 7363.0
This will work.
SELECT TheOrderids.PaidDate, MAX(Price) AS Total
,sum(theorderids.Discount) As Discount
,(MAX(Price) - sum(theorderids.Discount)) AS [Net Total]
From
(SELECT PaidDate ,SUM(Price ) AS Price
FROM Orders
WHERE Orders.PaidDate BETWEEN '8/17/2015' AND'8/19/2015'
GROUP BY Orders.PaidDate
) AS Orders
INNER JOIN theorderids ON Orders.PaidDate = theorderids.PaidDate
GROUP BY theorderids.PaidDate
ORDER BY theorderids.PaidDate ;
Try this way
SELECT Orders.PaidDate
, #pR AS Total
,sum(theorderids.Discount) As Discount
,(#pR - sum(theorderids.Discount)) AS [Net Total]
From
(SELECT ROW_NUMBER() OVER(ORDER BY Orders.PaidDate ) AS Row, OrderId, PaidDate
FROM Orders
WHERE Orders.PaidDate BETWEEN '8/17/2015' AND'8/18/2015'
GROUP BY Orders.OrderId, Orders.PaidDate) AS Orders
INNER JOIN theorderids ON Orders.OrderId = theorderids.ID
GROUP BY Orders.PaidDate ;
Hi i have a query which i need to show the number of transactions a user made,per day with the EUR equivalent of each transaction.
The query below does do that (find the eur equivalent by getting an average rate) but because the currencies are different i get the results by currency instead and not by total. what the query returns is:
Numb Transactions,Date, userid,transaction_type,total value (per currency),eur_equiv
1 12/12, 2, test 5 10
2 12/12,2, test 2 2
whereas i want it to return
Numb Transactions,Date, userid,transaction_type,total value (per currency),eur_equiv
1 12/12, 2, test 7 12
the query is shown below
SELECT COUNT(DISTINCT(ot.ID)) AS 'TRANSACTION COUNTER'
,CONVERT(VARCHAR(10) ,ot.CREATED_ON ,103) AS [DD/MM/YYYY]
,lad.ci
,ot.TRA_TYPE
,c.C_CODE
,CASE
WHEN op.CURRENCY_ID='CURRENCY-002' THEN SUM(CAST(op.IT_AMOUNT AS MONEY))
/(
SELECT AVG(CAST(cr.B_RATE AS MONEY)) AS AVG_RATE
FROM C_RATE cr
WHERE cr.CURRENCY_ID = 'CURRENCY-002'
)
WHEN op.CURRENCY_ID='-CURRENCY-005' THEN SUM(CAST(op.IT_AMOUNT AS MONEY))
/(
SELECT AVG(CAST(cr.B_RATE AS MONEY)) AS AVG_RATE
FROM C_RATE cr
WHERE cr.CURRENCY_ID = 'CURRENCY-005'
)
WHEN op.CURRENCY_ID='CURRENCY-006' THEN SUM(CAST(op.IT_AMOUNT AS MONEY))
/(
SELECT AVG(CAST(cr.B_RATE AS MONEY)) AS AVG_RATE
FROM C_RATE cr
WHERE cr.CURRENCY_ID = 'CURRENCY-006'
)
ELSE '0'
END AS EUR_EQUIVAL
FROM TRANSACTION ot
INNER JOIN PAYMENT op
ON op.ID = ot.ID
INNER JOIN CURRENCY c
ON op.CURRENCY_ID = c.ID
INNER JOIN ACCOUNT a
ON a.ID = ot.ACCOUNT_ID
INNER JOIN ACCOUNT_DETAIL lad
ON lad.A_NUMBER = a.A_NUMBER
INNER JOIN CUST cus
ON lad.CI = cus.CI
WHERE ot.TRA_TYPE_ID IN ('INBANK-TYPE'
,'IN-AC-TYPE'
,'DOM-TRANS-TYPE')
AND ot.STATUS_ID = 'COMPLETED'
AND cus.BRANCH IN ('123'
,'456'
,'789'
,'789')
GROUP BY
lad.CI
,CONVERT(VARCHAR(10) ,ot.CREATED_ON ,103)
,c.C_CODE
,op.CURRENCY_ID
,ot.TRAN_TYPE_ID
HAVING SUM(CAST(op.IT_AMOUNT AS MONEY))>'250000.00'
ORDER BY
CONVERT(VARCHAR(10) ,ot.CREATED_ON ,103) ASC
SELECT MIN([Numb Transactions]
, Date
, UserID
, Transaction_type
, SUM([Total Value]
, SUM([Eur Equiv]
FROM (
... -- Your current select (without order by)
) q
GROUP BY
Date
, UserId
, Transaction_type
The problem resides most likely in a double row in your joins. What I do, is Select * first, and see what columns generate double rows. You might need to adjust a JOIN relationship for the double rows to disappear.
Without any resultsets, it's very hard to reproduce the error you are getting.
Check for the following things:
Select * returns only double rows on the data i will merge with an aggregate function. If the answer here is "NO", you will need to alter a JOIN relationship with a Subselect. I am thinking of that Account and Account detail table.
certain joins can create duplicate rows if the join cannot be unique enough. Maybe you will have to join on multiple things here, for example JOIN table1 ON table1.ID = table2.EXT_ID and table1.Contact = table2.Contact
Couple of things:
1) Consider using a function for:
SELECT AVG(CAST(cr.B_RATE AS MONEY)) AS AVG_RATE
FROM C_RATE cr
WHERE cr.CURRENCY_ID = 'CURRENCY-002' with the currencyID as a parameter
2) Would grouping sets work here?
3) was the sum on the case or on the individual whens?
sum(CASE ..) vs sum(cast(op.IT_Amount as money)
I'm creating an SQL statement that will return a month by month summary on sales.
The summary will list some simple columns for the date, total number of sales and the total value of sales.
However, in addition to these columns, i'd like to include 3 more that will list the months best customer by amount spent. For these columns, I need some kind of inline subquery that can return their ID, Name and the Amount they spent.
My current effort uses an inline SELECT statement, however, from my knowledge on how to implement these, you can only return one column and row per in-line statement.
To get around this with my scenario, I can of course create 3 separate in-line statements, however, besides this seeming impractical, it increases the query time more that necessary.
SELECT
DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth,
COUNT(OrderID) AS TotalOrders,
SUM(OrderTotal) AS TotalAmount,
(SELECT SUM(OrderTotal) FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS TotalCustomerAmount,
(SELECT OrderCustomerFK FROM Orders WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerID,
(SELECT CustomerName FROM Orders INNER JOIN Customers ON OrderCustomerFK = CustomerID WHERE DATE_FORMAT(OrderDate,'%M %Y') = OrderMonth GROUP BY OrderCustomerFK ORDER BY SUM(OrderTotal) DESC LIMIT 1) AS CustomerName
FROM Orders
GROUP BY DATE_FORMAT(OrderDate,'%m%y')
ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
How can i better structure this query?
FULL ANSWER
After some tweaking of Dave Barkers solution, I have a final version for anyone in the future looking for help.
The solution by Dave Barker worked perfectly with the customer details, however, it made the simpler Total Sales and Total Sale Amount columns get some crazy figures.
SELECT
Y.OrderMonth, Y.TotalOrders, Y.TotalAmount,
Z.OrdCustFK, Z.CustCompany, Z.CustOrdTotal, Z.CustSalesTotal
FROM
(SELECT
OrdDate,
DATE_FORMAT(OrdDate,'%M %Y') AS OrderMonth,
COUNT(OrderID) AS TotalOrders,
SUM(OrdGrandTotal) AS TotalAmount
FROM Orders
WHERE OrdConfirmed = 1
GROUP BY DATE_FORMAT(OrdDate,'%m%y')
ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC)
Y INNER JOIN
(SELECT
DATE_FORMAT(OrdDate,'%M %Y') AS CustMonth,
OrdCustFK,
CustCompany,
COUNT(OrderID) AS CustOrdTotal,
SUM(OrdGrandTotal) AS CustSalesTotal
FROM Orders INNER JOIN CustomerDetails ON OrdCustFK = CustomerID
WHERE OrdConfirmed = 1
GROUP BY DATE_FORMAT(OrdDate,'%m%y'), OrdCustFK
ORDER BY SUM(OrdGrandTotal) DESC)
Z ON Z.CustMonth = Y.OrderMonth
GROUP BY DATE_FORMAT(OrdDate,'%Y%m')
ORDER BY DATE_FORMAT(OrdDate,'%Y%m') DESC
Move the inline SQL to be a inner join query. So you'd have something like...
SELECT DATE_FORMAT(OrderDate,'%M %Y') AS OrderMonth, COUNT(OrderID) AS TotalOrders, SUM(OrderTotal) AS TotalAmount, Z.OrderCustomerFK, Z.CustomerName, z.OrderTotal as CustomerTotal
FROM Orders
INNER JOIN (SELECT DATE_FORMAT(OrderDate,'%M %Y') as Mon, OrderCustomerFK, CustomerName, SUM(OrderTotal) as OrderTotal
FROM Orders
GROUP BY DATE_FORMAT(OrderDate,'%M %Y'), OrderCustomerFK, CustomerName ORDER BY SUM(OrderTotal) DESC LIMIT 1) Z
ON Z.Mon = DATE_FORMAT(OrderDate,'%M %Y')
GROUP BY DATE_FORMAT(OrderDate,'%m%y'), Z.OrderCustomerFK, Z.CustomerName
ORDER BY DATE_FORMAT(OrderDate,'%y%m') DESC
You can also do something like:
SELECT
a.`y`,
( SELECT #c:=NULL ) AS `temp`,
( SELECT #d:=NULL ) AS `temp`,
( SELECT
CONCAT(#c:=b.`c`, #d:=b.`d`)
FROM `b`
ORDER BY b.`uid`
LIMIT 1 ) AS `temp`,
#c as c,
#d as d
FROM `a`
Give this a shot:
SELECT CONCAT(o.order_month, ' ', o.order_year),
o.total_orders,
o.total_amount,
x.sum_order_total,
x.ordercustomerfk,
x.customername
FROM (SELECT MONTH(t.orderdate) AS order_month,
YEAR(t.orderdate) AS order_year
COUNT(t.orderid) AS total_orders,
SUM(t.ordertotal) AS total_amount
FROM ORDERS t
GROUP BY MONTH(t.orderdate), YEAR(t.orderdate)) o
JOIN (SELECT MONTH(t.orderdate) AS ordermonth,
YEAR(t.orderdate) AS orderyear
SUM(t.ordertotal) 'sum_order_total',
t.ordercustomerfk,
c.customername
FROM ORDERS t
JOIN CUSTOMERS c ON c.customerid = o.ordercustomerfk
GROUP BY t.ordercustomerfk, MONTH(t.orderdate), YEAR(t.orderdate)) x ON x.order_month = o.order_month
AND x.order_year = o.order_year
ORDER BY o.order_year DESC, o.order_month DESC