I am stuck with the following problem: I would like to return from my query the orders which have yet to be paid with the amount of the order and my customer information.
Here is what the tables look like:
Taking the case of customer number 124. I can see that this one has placed 13 orders. But I only have 7 checks registered
And I can see that if I add the sum of the orders minus the sum of the payments I find a difference that corresponds to the last 3 orders that this customer has placed.
So the question is how do I bring out the commands 10382, 10371, 10368 with all that? Knowing that the solution must be able to be applied to all orders.
So I thought to myself maybe using the order and payment dates. What orders does my customer place between their last payment and today?
So I tried something like this
#last order date
WITH last_cmd AS
(
SELECT
customerNumber, od.orderNumber, orderDate last_orderDate,
shippedDate, SUM(quantityOrdered * priceEach) totcmd
FROM
orders o
LEFT JOIN
orderdetails od ON o.orderNumber = od.orderNumber
WHERE
status NOT LIKE 'Can%'
GROUP BY
orderDate
ORDER BY
customerNumber, orderDate DESC
),
#last payment date last_payment AS
(
SELECT
customerNumber, amount, paymentDate, checkNumber
FROM
payments
GROUP BY
paymentDate
ORDER BY
customerNumber, paymentDate DESC
)
SELECT *
FROM last_cmd lc
LEFT JOIN last_payment lp ON lc.customerNumber = lp.customerNumber
GROUP BY lc.orderNumber
HAVING MAX(paymentDate) NOT BETWEEN MAX(last_orderDate) AND NOW();
But as you can see the result is not really what is expected. Still taking customer 124 as an example, command 10382 does not appear. And when I do the comparison of other orders manually for other customers the results do not match.
Does anyone have an idea please?
Here is the query I tried before posting
WITH ALL_PAYMENTS AS (
WITH paymentsValues AS (
select customerNumber, checkNumber, YEAR(paymentDate) paymentYear, sum(amount) paymentValue
from payments
LEFT JOIN customers USING (customerNumber)
GROUP BY customerNumber, paymentYear)
SELECT
customerNumber,
checkNumber, #Cumul des commandes clients
paymentYear,
SUM(paymentValue) totalPaymentsValue
FROM
paymentsValues
GROUP BY
customerNumber,
checkNumber
WITH ROLLUP
HAVING checkNumber is null),
ALL_ORDERS AS(
WITH ordersValues AS (
select customerNumber, orderNumber, YEAR(orderDate) orderYear, sum(quantityOrdered*priceEach) AS orderValue
from orderdetails
LEFT JOIN orders USING (orderNumber)
GROUP BY orderNumber, orderYear)
SELECT
customerNumber,
orderNumber, #Cumul des commandes clients
orderYear,
SUM(orderValue) totalOrderValue
FROM
ordersValues
#where orderNumber = '10179'
GROUP BY
customerNumber,
orderNumber
WITH ROLLUP
HAVING orderNumber is null)
SELECT AO.customerNumber, totalOrderValue, totalPaymentsValue, totalOrderValue-totalPaymentsValue Diff
FROM ALL_ORDERS AO
LEFT JOIN ALL_PAYMENTS AP ON AP.customerNumber=AO.customerNumber
WHERE totalOrderValue-totalPaymentsValue > 0;
This should give a list op amount that have to be paid, per date:
WITH d as (
select distinct orderDate as `date` from orders
union
select distinct paymentDate as `date` from payments)
select
`date`,
`customerNumber`,
`ordersValue`,
`amountPayed`,
`ordersValue` - `amountPayed` NotPayed
from (
select
d.`date` as "date",
o.customerNumber as "customerNumber",
sum(quantityOrders*priceEach) ordersValue,
(select sum(amount)
from payments p
where o.customerNumber = p.customerNumber AND p.paymentDate <= d.`date`) as amountPayed
from orderdetails od
cross join d
inner join Orders o on od.orderNumber = o.orderNumber AND o.orderDate <= d.`date`
group by d.`date`, o.customerNumber
) orderListPerCustomer
WHERE `customerNumber` = 124
ORDER BY `date` DESC
;
It is impossible to add order info, because there is no order info in the payments
This query does not take into account the status of the order (which might be Cancelled)
NOTE: This code is not tested, so there could be typing errors...
Related
I'm trying to determine how many new people made an order in 2018. This looks straight forward enough but there is an error with putting calculated fields in the WHERE statement.
SELECT DISTINCT COUNT(c.customer_id)
FROM Customer c
LEFT JOIN
Orders o ON c.customer_id=o.customer_id
WHERE MIN(order_date) > '2017-12-31'
AND MIN(order_date) < '2019-01-01';
You can achieve this by putting a sequence number to the orders and then selecting the first row for each customer. Although, I'm not really sure why you're performing a count of the orders when you just want to consider the first orders. Nevertheless the below should work just fine.
SELECT count(res.customer_id) FROM (
SELECT c.customer_id,
ROW_NUMBER() OVER (PARTITION BY c.customer_id ORDER BY o.order_date ASC) row_num
FROM Customer c
LEFT JOIN Orders o ON c.customer_id=o.customer_id
WHERE o.order_date > '2017-12-31'
AND o.order_date < '2019-01-01'
) res WHERE res.row_num=1
Join with a subquery that finds the customers that were new in 2018.
SELECT COUNT(DISTINCT o.customer_id)
FROM Orders o
JOIN (
SELECT DISTINCT customer_id
FROM Orders
GROUP BY customer_id
HAVING MIN(order_date) > '2017-12-31'
) o1 ON o1.customer_id = o.customer_id
WHERE o.order_date < '2019-01-01';
There's also no need to join with Customers, since the customer ID is in Orders.
And the correct way to get the distinct count is COUNT(DISTINCT o.customer_id), not DISTINCT COUNT(o.customer_id).
Here's my orders table:
I want to select all orders excluding very first order of each customer (if customer has placed multiple orders).
So if a customer e.g. 215 has total 8 orders, then I will select his all last 7 orders excluding his very first order 70000 which was placed on 10 July 2017.
But if a customer e.g. 219 had placed only one order 70007, it must be selected by the query.
Using an anti-join approach:
SELECT o1.order_id, o1.customer_id, o1.order_date, o1.order_value
FROM orders o1
LEFT JOIN
(
SELECT customer_id, MIN(order_date) AS min_order_date, COUNT(*) AS cnt
FROM orders
GROUP BY customer_id
) o2
ON o1.customer_id = o2.customer_id AND
o1.order_date = o2.min_order_date
WHERE
o2.customer_site = 1 AND
(o2.customer_id IS NULL OR
o2.cnt = 1);
The idea here is to try to match each record in orders to a record in the subquery, which contains only first order records, for each customer. If we can't find a match, then such an order record cannot be the first.
You can try below -
select order_id,customer_id,order_date,order_Value
from tablename
group by order_id,customer_id,order_date,order_Value
having count(order_id)=1
union all
select order_id,customer_id,order_date,order_Value
from tablename a where order_date not in (select min(order_date) from tablename b
where a.customer_id=b.customer_id)
Solution
Dear #Tim Biegeleisen, your answer almost done. just add HAVING COUNT(customer_id)>1
So the query is below:
SELECT o1.order_id, o1.customer_id, o1.order_date, o1.order_value
FROM orders o1
LEFT JOIN (
SELECT customer_id, MIN(order_date) AS min_order_date
FROM orders
GROUP BY customer_id
HAVING COUNT(customer_id)>1
) o2
ON o1.customer_id = o2.customer_id AND
o1.order_date = o2.min_order_date
WHERE
o2.customer_id IS NULL;
I am trying to use a subquery to retrieve the oldest order for each customer. I want to select email_address, order_id, and order_date
Tables:
customers(customer_id, email_address)
orders(order_id, order_date, customer_id)
What I've tried:
I can get either the order_id or the order_date by doing
SELECT email_address,
(SELECT order_date /* or order_id */
FROM orders o
WHERE o.customer_id = c.customer_id
ORDER BY order_date LIMIT 1)
FROM customers c
GROUP BY email_address;
but if I try to do SELECT order_id, order_date in my subquery, I get the error:
Operand should contain 1 column(s)
You can solve this with a JOIN, but you need to be careful to only JOIN to the oldest values for a given customer:
SELECT c.email_address, o.order_id, o.order_date
FROM customers c
JOIN orders o ON o.customer_id = c.customer_id AND
o.order_date = (SELECT MIN(order_date) FROM orders o2 WHERE o2.customer_id = c.customer_id)
You could use a JOIN to get the result you want, or modify your query as below:
SELECT email_address,
(SELECT order_date
FROM orders o1
WHERE o1.customer_id = c.customer_id
ORDER BY order_date LIMIT 1) as `order_date`,
(SELECT order_id
FROM orders o2
WHERE o2.customer_id = c.customer_id
ORDER BY order_date LIMIT 1) as `order_id`
FROM customers c
GROUP BY email_address;
The JOIN is of your choice.
How can I select multiple columns from a subquery (in SQL Server) that should have one record (select top 1) for each record in the main query?
SELECT o.order_id, c.email_address, o.order_date
FROM customers c
INNER JOIN (
SELECT order_date, order_id, customer_id
FROM orders o
ORDER BY order_date
) as o on o.customer_id = c.customer_id
GROUP BY email_address;
I have this query...
CREATE VIEW CustOrderItems AS
SELECT CustFirstName, CustLastName, OrderNumber, OrderDate, ShipDate,
QuantityOrdered * QuotedPrice AS ItemTotal
FROM Customers NATURAL JOIN Orders NATURAL JOIN Order_Details;
After grouping the orders like this...
SELECT CustFirstName, CustLastName, OrderNumber, OrderDate, ShipDate,
QuantityOrdered * QuotedPrice AS ItemTotal
FROM Customers NATURAL JOIN Orders NATURAL JOIN Order_Details
GROUP BY OrderNumber
ORDER BY OrderNumber ASC;
I know need to calculate the sum of all the ItemTotal's added together?
Any help is much appreciated!
As has been mentioned in a comment already, you get sums in SQL with SUM, which should not be much of a surprise. It seems strange you know about GROUP BY, but not about SUM.
At this point I'd like to recommend to always aggregate before joining, not afterwards. You want orders with their customer information and their total price. So select from orders, join with customers, join with total prices. Once you want aggregates from different tables, this approach will save you some trouble.
SELECT
c.CustFirstName,
c.CustLastName,
o.OrderNumber,
o.OrderDate,
o.ShipDate,
od.OrderTotal
FROM Orders o
JOIN Customers c ON c.CustomerNumber = o.CustomerNumber
JOIN
(
SELECT
OrderNumber,
SUM(QuantityOrdered * QuotedPrice) AS OrderTotal
FROM Order_Details
GROUP BY OrderNumber
) od ON od.OrderNumber = o.OrderNumber
ORDER BY o.OrderNumber ASC;
I have a question my professor gave me, on making a statement that goes like this
How many customers are “whales” i.e., have spent, in their lifetime, more than $4,000? How many are “shrimps,” having spent less than $20?
This is the online database we are using: http://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all
run this query to create another table before helping me out if you can
CREATE TABLE ByCustomerOrders AS
SELECT
o.OrderID
, p.ProductName
, p.ProductID
, Price
, Quantity
, Price * Quantity AS subtotal
, c.CustomerID
, s.SupplierID
FROM OrderDetails AS od
LEFT JOIN Orders AS o
ON od.OrderID = o.OrderID
LEFT JOIN Products AS p
ON p.ProductID = od.ProductID
LEFT JOIN Customers AS c
on c.CustomerID = o.CustomerID
LEFT JOIN Suppliers AS s
ON s.SupplierID = p.SupplierID;
I am trying to combine every customers order together grouping the sum by the customerID and then showing it in the table as a row for each customer ID and total amount they have order from subtotal
SELECT customerID, SUM(subtotal) AS 'total_money_spent' FROM ByCustomerOrders GROUP BY customerID ORDER BY 'total_money_spent' DESC LIMIT 1;
That didn't seem to work as it shows a value of 111. anyone see an issue?
You have a LIMIT 1 at the end of your statement which will only show the first result.
When you run:
SELECT customerID, SUM(subtotal) AS 'total_money_spent' FROM ByCustomerOrders GROUP BY customerID ORDER BY 'total_money_spent' DESC;
It outputs all the totals grouped