Access 2002 SQL for joining three tables - sql

I have been trying to get this to work for a while now. I have 3 tables. First table has the Sales for customers which include the CustomerID, DateOfSales (Which always has the first of the month). The second table has the CustomerName, CustomerID. The third table has which customers buy what product lines. They are stored by CustomerID, ProductID.
I want to get a list (from one SQL hopefully) that has ALL the customers that are listed as buying a certain ProductID AND the maxDate from the Sales. I can get all of them IF there are sales for that customer. How the heck do I get ALL customers that buy the certain ProductID AND the maxDate from Sales or NULL if there is no sales found?
SalesList |CustomerList|WhoBuysWhat
----------|------------|-----------
maxDate |CustomerID |CustomerID
CustomerID| |ProductID=17
This is as close as I got. It gets all max dates but only if there have been sales. I want the CustomerID and a NULL for the maxDate if there were no sales recorded yet.
SELECT WhoBuysWhat.CustomerID, CustomerList.CustomerName,
Max(SalesList.MonthYear) AS MaxOfMonthYear FROM (CustomerList INNER
JOIN SalesList ON CustomerList.CustomerID = SalesList.CustomerID) INNER
JOIN WhoBuysWhat ON CustomerList.CustomerID = WhoBuysWhat.CustomerID
WHERE (((SalesList.ProductID)=17)) GROUP BY WhoBuysWhat.CustomerID,
CustomerList.CustomerName;
Is it possible or do I need to use multiple SQL statements? I know we should get something newer than Access 2002 but that is what they have.

You want LEFT JOINs:
SELECT cl.CustomerID, cl.CustomerName,
Max(sl.MonthYear) AS MaxOfMonthYear
FROM (CustomerList as cl LEFT JOIN
(SELECT sl.*
FROM SalesList sl
WHERE sl.ProductID = 17
) as sl
ON cl.CustomerID = sl.CustomerID
) LEFT JOIN
WhoBuysWhat wbw
ON cl.CustomerID = wbw.CustomerID
GROUP BY cl.CustomerID, cl.CustomerName;

Related

SQL - Create complete matrix with all variables even if null

please provide some assistance/guidance to solve the following:
I have 1 main table which indicates sales volumes by sales person per different product type.
Where a salesperson did not sell a particular product on a particular day, there is no record.
The intention is to create null value records for salesmen that did not sell a product on a specific day. The query must be dynamic as there are many more salesmen with sales over many days.
Thanks in advance
Just generate records for all sales persons, days, and products using cross join and then bring in the existing data:
select p.salesperson, d.salesdate, st.salestype,
coalesce(t.sales_volume, 0)
from (select distinct salesperson from t) p cross join
(select distinct salesdate from t) d cross join
(select distinct salestype from t) st left join
t
on t.salesperson = p.salesperson and
t.salesdate = d.salesdate and
t.salestype = st.salestype;
Note: You may have other tables that have lists of sales people, dates, and types -- and those can be used instead of the select distinct queries.

Show all customers who havent placed an order in a specific time frame

Fairly new to SQL and databases.... I have the following issue...
Database for a shipping company, three relevant tables for this problem are;
Customer (CustomerID, Name, Address etc)
Shipment (ShipmentID, ScheduleName, DepartDate, ArriveDate, DepartPort, ArrivePort)
CustomerOrder (CustomerID, ShipmentID, Fee etc)
I need to show
'All customers that have NOT placed an order within a specific year, i.e. 2019' Im struggling to find the correct query for this. Im working on sample data, there are 8 customers in the database, 3 of which have orders for shipments departing in 2019. Therefore the result im hoping to get is a list of the 5 remaining customers who did not have orders on these shipments.
I can easily show customer who have placed an order and those who have never placed an order however im struggling to show those who haven't placed an order in a specific timeframe.
Any ideas or tips would be greatly appreciated!
Thanks
EDIT***
Desired Result - Show the 5 customers who havent placed an order where the shipping depart date is in 2019
I have tried;
~
SELECT CustomerID from customer
LEFT OUTER JOIN customerorder
ON Customer.CustomerID = CustomerOrder.CustomerID
LEFT OUTER JOIN shipment
ON CustomerOrder.ShipmentID = Shipment.ShipmentID
WHERE shipment.DepartDate BETWEEN '2019-01-01' AND '2019-12-31'
AND CustomerOrder.CustomerID IS NULL
~
However this bring back no results.
The three tables have the following information
Customer - (simply table of customer details) (CustomerID, Name, Address, Tel, Type, Size, RegisteredSince)
Shipment - (Details each shipment scheduled) (ShipmentID, ScheduleName, DepartDate, DepartPort, ArriveDate, ArrivePort, Season)
CustomerOrder - (Details customer order, but not individual items on an order) (OrderID, ShipmentID, CustomerID)
Im not sure if its the join thats the problem? There are 4 shipments in 2019 in the sample data with a total of 3 customers. I need to show the customerID's of the 5 customers who didnt place an order within these dates.
Ive tried a few different queries, have been searching online but im new to this and not quite sure where im going wrong. I am able to identify customers who have never placed an order but as soon as I add the date ranges i get no results.
Desired Result - Show the 5 customers who havent placed an order where the shipping depart date is in 2019
Use NOT EXISTS:
SELECT c.*
FROM Customer c
WHERE NOT EXISTS (SELECT 1
FROM CustomerOrder co JOIN
Shipment sh
ON co.shipmentID = sh.ShipmentID
WHERE c.CustomerID = co.CustomerID AND
sh.DepartDate >= '2019-01-01' AND
sh.DepartDate < '2020-01-01'
);
I don't now from your relations where do you save the order date, but you could change anything if it is needed. I have used DepartDate to mange orders Year that are different from 2019:
Example:
SELECT c.*
FROM Customer c
INNER JOIN CustomerOrder co ON c.CutomerID = co.CutomerID
INNER JOIN Shipment sh ON co.shipmentID = sh.ShipmentID
WHERE YEAR(sh.DepartDate) <> 2019
Get all cutomers data where DepartDate not equal to 2019
I think this could be the solution that you want, here is full-query.
Sub-Query means you get all customerID-s that made orders on 2019 and we are exclude theme with not in ...
SELECT c.*
FROM Customer c
INNER JOIN CustomerOrder co ON c.CutomerID = co.CutomerID
INNER JOIN Shipment sh ON co.shipmentID = sh.ShipmentID
WHERE YEAR(sh.DepartDate) <> 2019 AND c.CutomerID
NOT IN (SELECT c.*
FROM Customer c
INNER JOIN CustomerOrder co ON c.CutomerID = co.CutomerID
INNER JOIN Shipment sh ON co.shipmentID = sh.ShipmentID
WHERE YEAR(sh.DepartDate) = 2019)
Just do a left outer join on orders by customerId in the appropriate date range where the customerID doesn't exist:
select c.*
from customers c
left outer join (
select customerID
from CustomerOrder o
join Shipment s on s.ShipmentID=o.ShipmentID
where DepartDate>='2020-01-01' and DepartDate<'2021-01-01'
) x on x.customerID=c.customerID
where x.customerid is null
The subquery selects every single customerID who ordered in the date range.
The left outer join and "customerid is null" does a negative match on those customers who don't exist in our subquery.

stacking data from two tables with different dates

I have two tables, Sales and Returns. They have CustomerID, ProductCode, Name, SalesDate, SalesWeek, SalesAmount and ReturnsDate, ReturnsWeek, ReturnsAmount. What I really want to do is just join these tables and stack them on top of each other so the client has data in a single report for both sales and returns.
Sales and Returns dates are different but the product code, customer ID and Name can be same for a record in output table. For instance Customer A bought a product last month and returned it next month, so his record can appear in returns table.
To achieve this I have tried using union by selecting all columns between both tables but I am getting a mix of records for sales and returns with no consistency. All I want to do is see Nulls for Customers who have no business with Returns and vice versa. I was thinking Left Join in this case should work but it isn't working. So I am seeing mixed up data in all columns for Sales and Returns amounts. Attached is the picture that has two tables, the output I am seeing and the out put I want to see. Also I am performing Weekly aggregations for Sales and Returns amounts. What is the best and easiest way to achieve this ? I am sorry I may have not structured my question properly but the image might help #NewToSQL
Presumably, a customer can purchase a given product more than once. If so, a full join is the right solution, but you need a bit more logic to ensure non-duplication in the results:
select . . .
from (select s.*,
row_number() over (partition by product_code, customer_id order by (select NULL)) as seqnum
from sales s
) s full join
(select r.*,
row_number() over (partition by product_code, customer_id order by (select NULL)) as seqnum
from returns r
) r
on s.product_code = r.product_code and s.customer_id = r.customer_id;
I am leaving the name out, because I assume it is defined by the customer id.
You need to do a FULL JOIN sales table with returns table on those columns that you mentioned.
Something like :
SELECT *
FROM sales s
FULL JOIN returns r
ON s.product_code = r.product_code
AND s.customerid = r.customer_id

sql sum from two tables

I've got two separate tables in sqlite called invoices and purchases and I am using the query below to retrieve the sum of all the invoices and purchases that related to project 7. The thing is the invoices have three records and the value returned in sql is correct, however the purchase equivalent is wrong as there is only one record, but the returned value is multiplied by three.
SELECT sum(invoice.invoice_net) As Sales, sum(purchase.total_order) As Purchases
FROM invoice
LEFT JOIN purchase
ON purchase.projectID=invoice.projectID
WHERE invoice.projectID=7
How can I join these two statements so I get the data returned correctly. I know individually they work fine. I've tried Union, but that puts the data into one column.
SELECT sum(invoice.invoice_net) As Sales
FROM invoice
WHERE projectID=7
SELECT sum(purchase.order_total) As Purchases
FROM purchase
WHERE projectID=7
One option is to sum the results using subqueries and then perform the outer join:
SELECT invoice.Sales, purchase.Purchases
FROM (
SELECT sum(invoice.invoice_net) As Sales, projectID
FROM invoice
GROUP BY projectID
) invoice LEFT JOIN (
SELECT sum(total_order) As Purchases, projectID
FROM purchase
GROUP BY projectID
) purchase ON purchase.projectID=invoice.projectID
WHERE invoice.projectID=7
Another option would be to use a correlated subquery:
SELECT sum(i.invoice_net) As Sales,
(SELECT sum(p.total_order)
FROM purchase p
WHERE p.projectID = i.projectID) As Purchases
FROM invoice i
WHERE i.projectID=7

SQL: Join 2 tables and return multiple rows from second table based on key of first table

I have one table 'Customers', with a key of customerid.
There is another table PaymentTotals which also has a customerid column. This table stores amounts paid by a customer (PaymentAmount) in a given week (weeknumber field). This implies that in the PaymentTotals table there may be several rows for any one customerid, the difference being the weeknumber for any of these rows.
I am trying to build a query in MSSQL that joins the two tables and will return for a given customerid the PaymentAmount for each different weeknumber.
It is not clear to me how to build this query. Any advice? Thanks.
SELECT *
FROM Customers C INNER JOIN PaymentTotals PT
ON C.customerid = PT.customerid
If you have multiple Payments made by one customer in a given week and want to get total by week you could do something like ....
SELECT C.customerid
,PT.WeekNumber
,SUM(PT.Payment_Column) AS TotalPayment
FROM Customers C INNER JOIN PaymentTotals PT
ON C.customerid = PT.customerid
GROUP BY C.customerid, PT.WeekNumber