SQL Query: joining three tables to generate a Sales Report of Spend - sql

I normally work with MySQL so not sure how to get a query to work on SQL.
I have 3 tables:
Table1
ODBC_ORDER_LINE_ALL
This contains ORDER_LINE_NETT_TOTAL and also the ORDER_LINE_ORDER_ID
Table 2
ODBC_ORDER_ALL
This contains the ORDER_ID and also the ORDER_ACCOUNT_ID
Table 3
ODBC_ACCOUNT
This contains the ACCOUNT_ACCID and some other information on the account we may need in the future, hence why we are adding it.
I am joining table 1,2,3 together using the above constraints.
What I want to be able to do is generate a Sales Report of Spend showing Account Number and Total Spend but I can't seem to get the syntax correct.
Any help much appreciated.
Here are the tables:
ODBC_ORDER_LINE_ALL
ORDER_LINE_ID
ORDER_LINE_ORDER_ID
ORDER_LINE_DATE
ORDER_LINE_MEDIACODE
ORDER_LINE_SOURCE
ORDER_LINE_PRODUCT_ID
ORDER_LINE_PRODUCT_CODE
ORDER_LINE_PRODUCT_NAME
ORDER_LINE_QUANTITY
ORDER_LINE_NETT_PRICE
ORDER_LINE_VAT_CODE
ORDER_LINE_VAT_RATE
ORDER_LINE_VAT
ORDER_LINE_NETT_TOTAL
ORDER_LINE_VAT_TOTAL
ORDER_LINE_GROSS_TOTAL
ORDER_LINE_UNIT_COST
ORDER_LINE_COST_CURRENCY
ORDER_LINE_COST_EXCHANGE_RATE
ORDER_LINE_TYPE
ORDER_LINE_STAGE
ORDER_LINE_STAGE_DATE
ORDER_LINE_INVOICE_ID
ORDER_LINE_INVOICE_DATE
ORDER_LINE_KIT_COMPONENT
ORDER_LINE_KIT_LINE_ID
ORDER_LINE_USER
ODBC_ORDER_ALL
ORDER_ID
ORDER_TYPE
ORDER_MEDIA_CODE_ID
ORDER_MEDIA_CODE
ORDER_MEDIA_SUBCODE
ORDER_TAKEN_BY
ORDER_DATE
ORDER_ACCOUNT_ID
ORDER_DELIVERY_ACCOUNT_ID
ORDER_SOURCE_ID
ORDER_SOURCE
ORDER_WEB_ORDER_ID
ORDER_MULTI_CLIENT_ID
ORDER_MULTI_CLIENT
ODBC_ACCOUNT
ACCOUNT_ACCID
ACCOUNT_ACC_TYPE
ACCOUNT_REF
ACCOUNT_TITLE
ACCOUNT_FORENAME
ACCOUNT_SURNAME
ACCOUNT_COMPANY_NAME
ACCOUNT_HOUSE_NAME
ACCOUNT_ADD1
ACCOUNT_ADD2
ACCOUNT_ADD3
ACCOUNT_ADD4
ACCOUNT_POSTCODE
ACCOUNT_COUNTRY
ACCOUNT_PHONE1
ACCOUNT_PHONE2
ACCOUNT_FAX1
ACCOUNT_FAX2
ACCOUNT_EMAIL
ACCOUNT_WEBSITE
ACCOUNT_PRICELIST_ID
ACCOUNT_MEDIACAMPAIGN_ID
ACCOUNT_CREATED_DATE

Assuming that the table names are 'Table 1' ODBC_Order_Line_All, 'Table 2' ODBC_Order_All, 'Table 3' ODBC_Account, then you simply need to join the three tables on the relevant joining columns, and sum the order line nett total entries for each account:
SELECT A.Account_AccID, SUM(L.Order_Line_Nett_Total) AS TotalSpend
FROM ODBC_Account AS A
JOIN ODBC_Order_All AS O ON A.Account_Acc_ID = O.Order_Account_ID
JOIN ODBC_Order_Line_All AS L ON O.Order_ID = L.Order_Line_Order_ID
GROUP BY A.Account_AccID;
However, while there is nothing but the Account_AccID selected from ODBC_Account, there is no actual need to select from the ODBC_Account table; you can join just the two tables, yielding a simpler query:
SELECT O.Order_Account_ID AS Acount_AccID, SUM(L.Order_Line_Nett_Total) AS TotalSpend
FROM ODBC_Order_All AS O ON A.Account_Acc_ID = O.Order_Account_ID
JOIN ODBC_Order_Line_All AS L ON O.Order_ID = L.Order_Line_Order_ID
GROUP BY Account_AccID;
There is nothing here that is different in MySQL from any other SQL DBMS, so your knowledge of MySQL should transfer directly.

Related

Expand Join to not limit data

I have a weird question - I understand that Joins return matching data based on the 'ON' stipulation, however the problem I am facing is I need the Business date back for both tables but at the same time i need to join on the date in order to get the totals correct
See below code:
Select
o.Resort,
o.Business_Date,
Occupied,
Comps,
House,
ADR,
Room_Revenue,
Occupied-(Comps+House) AS DandT,
Coalesce(gd.Projected_Occ1,0) AS Projected_Occ1,
Occupied-(Comps+House)+Coalesce(gd.Projected_Occ1,0) as Total
from Occupancy o
left join Group_Details_HF gd
on o.Business_Date = gd.Business_Date
and o.Resort = gd.resort
UNION ALL
select
o.Resort,
o.Business_Date,
Occupied,
Comps,
House,
ADR,
Room_Revenue,
Occupied-(Comps+House) AS DandT,
Coalesce(gd.Projected_Occ1,0) AS Projected_Occ1,
Coalesce(Occupied-(Comps+House),0)+Coalesce(gd.Projected_Occ1,0) as Total
from Occupancy_Forecast o
FULL OUTER JOIN Group_Details_HF gd
on o.Business_Date = gd.Business_Date
and o.Resort = gd.resort
Currently, this gives me the desired results from the Occupancy and Occupancy forecast table however when the business date does not exist in the occupancy forecast table it ignores the group_details table, I need the results to combine the dates when they exist in both or give the unique results for each when there is no match
I have decided to create another pivot table storing the details from Group_Details_HF and then Union together the two tables which has given me the desired result rather than fiddling with the join :)

Access 2013 SQL, three tables, two using sum wrong results

Can someone please help me with this issue? I've scoured the Internet looking at dozens of examples, but i just can't find a solution that works.
I am using Access 2013. The problem is that I am trying to make a query that will highlight all part numbers from a supplier that either has customer back orders and/or overdue deliveries.
I am using three tables:
tbl_Inventory_Master which I require the part number, on hand stock value, and the supplier code.
For any back orders I need to join the tbl_Customer_Back_Order table as I need the count of back order lines and the sum of the back order quantity.
If the supplier has a late delivery, then I need to add the tbl_On_Order table showing the count of overdue deliveries and the sum of the overdue quantities.
The query is retrieving the data but the returned quantities are double what they should be.
SELECT
I.Inventory_Part_Num, I.Description, I.On_Hand_Stock,
COUNT (B.Part_Number) AS Back_Order_Count, SUM(B.Back_Order_Qty) as BO_Qty,
COUNT(O.Part_Number) AS Late_Deliveries_Count, SUM(O.Order_Qty) AS Late_Qty
FROM (tbl_Inventory_Master AS I
LEFT OUTER JOIN tbl_Customer_Back_Order AS B
ON I.Inventory_Part_Num = B.Part_Number)
LEFT OUTER tbl_On_Order AS O
ON I.Inventory_Part_Num = O.Part_Number
WHERE
I.Customer_Code = '274' AND
O.Due_Date < [ENTER TODAYS DATE IN FORMAT DD/MM/YYYY]
GROUP BY I.Inventory_Part_Num, I.Description, I.On_Hand_Stock
For example, for the part number 2022940 I should have 10 back order lines and an overdue quantity of 43. Instead, the query is returning 20 back order lines and an overdue quantity sum of 86.
From the on order table I have three orders totaling 144 pieces, instead the query is returning 960.
Can someone please advise, as this is driving me crazy?
You are joining along unrelated dimensions, so you need to aggregate before joining:
SELECT I.Inventory_Part_Num, I.Description, I.On_Hand_Stock,
B.Back_Order_Count, B.BO_Qty,
O.Late_Deliveries_Count, O.Late_Qty
FROM (tbl_Inventory_Master AS I LEFT OUTER JOIN
(SELECT B.Part_Number, COUNT(*) as Back_Order_Count,
SUM(B.Back_Order_Qty) as BO_Qty
FROM tbl_Customer_Back_Order AS B
GROUP BY B.Part_Number
) as B
ON I.Inventory_Part_Num = B.Part_Number
) LEFT JOIN
(SELECT O.Part_Number, COUNT(O.Part_Number) AS Late_Deliveries_Count,
SUM(O.Order_Qty) AS Late_Qty
FROM tbl_On_Order AS O
WHERE O.Due_Date < [ENTER TODAYS DATE IN FORMAT DD/MM/YYYY]
GROUP BY O.Part_Number
) as O
ON I.Inventory_Part_Num = O.Part_Number
WHERE I.Customer_Code = '274';
Notice the outer aggregation is no longer needed.

Total price from different tables

I have a database with customers, items and orders. This is an exam project, so is maybe not the best for real life. I have this problem. I want a list of what all our customers have bought and a total price of that, but I can't get anything to work.
select Kunder.navn,Ordre.*, Indeholder.antal, Varer.*
from Kunder
join Ordre on Kunder.kunde_nr=Ordre.kunde_nr
join Indeholder on Ordre.ordre_nr=Indeholder.ordre_nr
join Varer on Varer.vare_nr=Indeholder.vare_nr
where er_industri=0
order by bestillingsdato
I have tried a lot like:
sum (Indeholder.antal * Varer.privat_pris) as total
group by Ordre.ordre_nr
But I just can't get anything that I've tried, to give me what I'm looking for.
I hope that you want to help me, and that you understand what I mean (I'm not a native english speaker).
I have uploaded an image of our mapping, so you can see what our database look like:
And for clarity, just a translation:
Kunder = customers
Varer = items
Ordre = orders
Indeholder = includes
Just add more columns on your group by clause.
Apart from the aggregate functions [SUM(), COUNT(), AGV()] the same list of columns must be present at the group by clause
and at select clause:
So, generally:
select <col1, col2, col3...>, SUM(...)
from ...
group by <col1, col2, col3...>
If you want a per customer AND order groupping:
select Kunder.navn, Ordre.ordre_nr, sum (Indeholder.antal * Varer.privat_pris) as total
from Kunder
join Ordre on Kunder.kunde_nr=Ordre.kunde_nr
join Indeholder on Ordre.ordre_nr=Indeholder.ordre_nr
join Varer on Varer.vare_nr=Indeholder.vare_nr
where er_industri=0
group by Kunder.navn, Ordre.ordre_nr
You could also do a per customer groupping:
select Kunder.navn, sum (Indeholder.antal * Varer.privat_pris) as total
from Kunder
join Ordre on Kunder.kunde_nr=Ordre.kunde_nr
join Indeholder on Ordre.ordre_nr=Indeholder.ordre_nr
join Varer on Varer.vare_nr=Indeholder.vare_nr
where er_industri=0
group by Kunder.navn

SUM(a*b) not working

I have a PHP page running in postgres. I have 3 tables - workorders, wo_parts and part2vendor. I am trying to multiply 2 table column row datas together, ie wo_parts has a field called qty and part2vendor has a field called cost. These 2 are joined by wo_parts.pn and part2vendor.pn. I have created a query like this:
$scoreCostQuery = "SELECT SUM(part2vendor.cost*wo_parts.qty) as total_score
FROM part2vendor
INNER JOIN wo_parts
ON (wo_parts.pn=part2vendor.pn)
WHERE workorder=$workorder";
But if I add the costs of the parts multiplied by the qauntities supplied, it adds to a different number than what the script is doing. Help....I am new to this but if someone can show me in SQL I can modify it for postgres. Thanks
Without seeing example data, there's no way for us to know why you're query totals are coming out differently that when you do the math by hand. It could be a bad join, so you are getting more/less records than you expected. It's also possible that your calculations are off. Pick an example with the smallest number of associated records & compare.
My suggestion is to add a GROUP BY to the query:
SELECT SUM(p.cost * wp.qty) as total_score
FROM part2vendor p
JOIN wo_parts wp ON wp.pn = p.pn
WHERE workorder = $workorder
GROUP BY workorder
FYI: MySQL was designed to allow flexibility in the GROUP BY, while no other db I've used does - it's a source of numerous questions on SO "why does this work in MySQL when it doesn't work on db x...".
To Check that your Quantities are correct:
SELECT wp.qty,
p.cost
FROM WO_PARTS wp
JOIN PART2VENDOR p ON p.pn = wp.pn
WHERE p.workorder = $workorder
Check that the numbers are correct for a given order.
You could try a sub-query instead.
(Note, I don't have a Postgres installation to test this on so consider this more like pseudo code than a working example... It does work in MySQL tho)
SELECT
SUM(p.`score`) AS 'total_score'
FROM part2vendor AS p2v
INNER JOIN (
SELECT pn, cost * qty AS `score`
FROM wo_parts
) AS p
ON p.pn = p2v.pn
WHERE p2n.workorder=$workorder"
In the question, you say the cost column is in part2vendor, but in the query you reference wo_parts.cost. If the wo_parts table has its own cost column, that's the source of the problem.

outer query to list only if its rowcount equates to inner subquery

Need help on a query using sql server 2005
I am having two tables
code
chargecode
chargeid
orgid
entry
chargeid
itemNo
rate
I need to list all the chargeids in entry table if it contains multiple entries having different chargeids
which got listed in code table having the same charge code.
data :
code
100,1,100
100,2,100
100,3,100
101,11,100
101,12,100
entry
1,x1,1
1,x2,2
2,x3,2
11,x4,1
11,x5,1
using the above data , it query should list chargeids 1 and 2 and not 11.
I got the way to know how many rows in entry satisfies the criteria, but m failing to get the chargeids
select count (distinct chargeId)
from entry where chargeid in (select chargeid from code where chargecode = (SELECT A.chargecode
from code as A join code as B
ON A.chargecode = B.chargeCode and A.chargetype = B.chargetype and A.orgId = B.orgId AND A.CHARGEID = b.CHARGEid
group by A.chargecode,A.orgid
having count(A.chargecode) > 1)
)
First off: I apologise for my completely inaccurate original answer.
The solution to your problem is a self-join. Self-joins are used when you want to select more than one row from the same table. In our case we want to select two charge IDs that have the same charge code:
SELECT DISTINCT c1.chargeid, c2.chargeid FROM code c1
JOIN code c2 ON c1.chargeid != c2.chargeid AND c1.chargecode = c2.chargecode
JOIN entry e1 ON e1.chargeid = c1.chargeid
JOIN entry e2 ON e2.chargeid = c2.chargeid
WHERE c1.chargeid < c2.chargeid
Explanation of this:
First we pick any two charge IDs from 'code'. The DISTINCT avoids duplicates. We make sure they're two different IDs and that they map to the same chargecode.
Then we join on 'entry' (twice) to make sure they both appear in the entry table.
This approach gives (for your example) the pairs (1,2) and (2,1). So we also insist on an ordering; this cuts to result set down to just (1,2), as you described.