How to find result set from two different date comparisons? - sql

How to find result set from two different date comparisons
How to find period1_label_cost, period2_label_cost in this query without using this query ?
Only period1_label_cost column value is getting
select distinct customers.id as customer_id, customers.first_name as first_name, customers.last_name as last_name, SUM(orders.total_cost) as period1_label_cost
from customers inner join orders
on customers.id= orders.customer_id
where
date(orders.created_at) between 'start_date1' and 'end_date1'
group by customers.id , customers.first_name, customers.last_name, customers.preferred
having(SUM(orders.total_cost) > sales_exceeded
intersect
select distinct customers.id as customer_id, customers.first_name as first_name, customers.last_name as last_name,
customers.preferred as preferred, SUM(orders.total_cost) as period2_label_cost
from customers inner join orders
on customers.id= orders.customer_id
where
date(orders.created_at) between start_date2 and end_date2
group by customers.id , customers.first_name, customers.last_name, customers.preferred
having( SUM(orders.total_cost) < sales_below) order by first_name asc

Are you looking for mere joins? Put your two queries in your FROM clause and join them on customer_id, then join with the customers table and show the results.
select
c.id as customer_id,
c.first_name,
c.last_name,
c.preferred,
period1.label_cost as period1_label_cost,
period2.label_cost as period2_label_cost
from
(
select
customer_id,
sum(total_cost) as label_cost
from orders
where date(created_at) between <start_date1> and <end_date1>
group by customer_id
having sum(total_cost) > <sales_exceeded>
) period1
join
(
select
customer_id,
sum(total_cost) as label_cost
from orders
where date(created_at) between <start_date2> and <end_date2>
group by customer_id
having sum(total_cost) < <sales_below>
) period2 on period2.customer_id = period1.customer_id
join customers c on c.id = period1.customer_id;

Related

Order customers based on the purchases sum

I have this SQL
SELECT customers.first_name
FROM customers
INNER JOIN orders ON customer.id = orders.customer_id
GROUP BY first_name
HAVING SUM(orders.price) > 100;
But I want all customers to be listed in a table from the highest purchase price of their order to the lowest.
You can use next simple ORDER BY:
SELECT customers.first_name, SUM(orders.price) orders_price
FROM customers
INNER JOIN orders ON customers.id = orders.customer_id
GROUP BY first_name
ORDER BY orders_price DESC;
MySQL order by fiddfe
Also you can use LEFT JOIN and COALESCE function for select customers without orders:
SELECT
customers.first_name,
COALESCE(SUM(orders.price), 0) orders_price FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id
GROUP BY first_name
ORDER BY orders_price DESC;
MySQL LEFT JOIN & COALESCE

How can i get all the MAX values from a certain column in a dataset in PostgreSQL

I'm asked to find the top user for different countries, however, one of the countries has 2 users with the same amount spent so they should both be the top users, but I can't get the max value for 2 values in this country.
Here is the code:
WITH t1 AS (
SELECT c.customerid,SUM(i.total) tot
FROM invoice i
JOIN customer c ON c.customerid = i.customerid
GROUP BY 1
ORDER BY 2 DESC
),
t2 AS (
SELECT c.customerid as CustomerId ,c.firstname as FirstName,c.lastname as LastName, i.billingcountry as Country,MAX(t1.tot) as TotalSpent
FROM t1
JOIN customer c
ON c.customerid = t1.customerid
JOIN invoice i ON i.customerid = c.customerid
GROUP BY 4
ORDER BY 4
)
SELECT *
FROM t2
BILLINGCOUNTRY is in Invoice, and it has the name of all the countries.
TOTAL is also in invoice and it shows how much is spent for each purchase by Customer (so there are different fees and taxes for each purchase and total shows the final price payed by the user at each time)
Customer has id,name,last name and from its' ID I'm extracting the total of each of his purchases
MAX was used after finding the sum for each Customer and it was GROUPED BY country so that i could find the max for each country, however I can't seem to find the max of the last country that had 2 max values
Use rank() or dense_rank():
SELECT c.*, i.tot
FROM (SELECT i.customerid, i.billingCountry, SUM(i.total) as tot,
RANK() OVER (PARTITION BY i.billingCountry ORDER BY SUM(i.total) DESC) as seqnum
FROM invoice i
GROUP BY 1, 2
) i JOIN
customer c
ON c.customerid = i.customerid
WHERE seqnum = 1;
The subquery finds the amount per customer in each country -- and importantly calculates a ranking for the combination with ties having the same rank. The outer query just brings in the additional customer information that you seem to want.
here is how it worked for me since i was restricted from using many Commands such RIGHT JOIN and RANK() (As what Gordon Linoff suggessted) so i had to create a 3rd case for the anamoly and join it using union. this solution works only on this case, the good solution is the one posted by Gordon Linoff:
WITH t1 AS (
SELECT c.customerid,SUM(i.total) tot
FROM invoice i
JOIN customer c ON c.customerid = i.customerid
GROUP BY 1
ORDER BY 2 DESC
),
t2 AS (
SELECT c.customerid as CustomerId ,c.firstname as FirstName,c.lastname as LastName, i.billingcountry as Country,MAX(t1.tot) as TotalSpent
FROM t1
JOIN customer c
ON c.customerid = t1.customerid
JOIN invoice i ON i.customerid = c.customerid
GROUP BY 4
ORDER BY 4
) ,
t3 AS (
SELECT DISTINCT c.customerid as CustomerId ,c.firstname as FirstName,c.lastname as LastName, i.billingcountry as Country,t1.tot as TotalSpent
FROM t1
JOIN customer c
ON c.customerid = t1.customerid
JOIN invoice i ON i.customerid = c.customerid
WHERE i.billingcountry = 'United Kingdom'
ORDER BY t1.tot DESC
LIMIT 2
)
SELECT *
FROM t2
UNION
SELECT * FROM t3
ORDER BY t2.country

Return the rows that are above average

I'm trying to find the countries from which the number of orders is higher than the average. This is as far as I got. The problem is (see picture) that the count of orders for each country is off, as it should be different for everyone
SELECT avg(NumberOrders) as avg,
Customers.Country,
NumberOrders
FROM Customers,
(SELECT COUNT(Orders.OrderId) AS NumberOrders
FROM Customers JOIN
Orders ON Customers.CustomerID = Orders.CustomerID
GROUP BY Customers.Country) nested
GROUP BY Customers.Country
HAVING NumberOrders > avg;
Output
If your DBMS supports Windowed Aggregates (almost all besides MySQL & Access):
select *
from
(
SELECT Customers.Country,
COUNT(Orders.OrderId) AS NumberOrders, -- count per country
AVG(COUNT(Orders.OrderId)) OVER () AS avgOrders -- average count
FROM Customers
JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
GROUP BY Customers.Country
) nested
WHERE NumberOrders > avgOrders
Edit:
For DBMSes not supporting Windowed Aggregates it's way more complicated:
SELECT Customers.Country,
COUNT(Orders.OrderId) AS NumberOrders -- count per country
FROM Customers
JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
GROUP BY Customers.Country
HAVING COUNT(Orders.OrderId) >
( select avg(NumberOrders)
from
(
SELECT Customers.Country,
COUNT(Orders.OrderId) AS NumberOrders -- count per country
FROM Customers
JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
GROUP BY Customers.Country
) AS dt
)
If the DBMS supports Common Table Expressions this can be simplified:
with cte as
(
SELECT Customers.Country,
COUNT(Orders.OrderId) AS NumberOrders -- count per country
FROM Customers
JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
GROUP BY Customers.Country
)
select *
from cte
WHERE NumberOrders >
(
select avg(NumberOrders) from cte
)

Conditions in SQL subqueries

I made this query and now I have to find different ways which will return same results.
SELECT CompanyName, COUNT(Orders.OrderID) Orders
FROM Customers LEFT OUTER JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Country LIKE 'Germany' OR Country LIKE 'Brazil'
GROUP BY CompanyName HAVING COUNT(Orders.OrderID) >= 10
ORDER BY Orders ASC;
So I made this but I have no idea where should I put the ">=10" condition. Could someone tell me how to do it? I tried some ways but it didn't work.
SELECT CompanyName, (SELECT COUNT(OrderID) FROM Orders WHERE Customers.CustomerID = Orders.CustomerID) AS Orders
FROM Customers
WHERE Country LIKE 'Germany' OR Country LIKE 'Brazil'
ORDER BY Orders ASC;
It's for MS SQL Server...
SELECT CompanyName, COUNT(Orders.OrderID) Orders
FROM Customers JOIN Orders ON Customers.CustomerID = Orders.CustomerID
WHERE Country IN('Germany','Brazil')
GROUP BY CompanyName
HAVING COUNT(Orders.OrderID) >= 10
ORDER BY Orders ASC;
SELECT
COMPANYNAME,
( SELECT
COUNT ( ORDERID )
FROM
ORDERS
WHERE
CUSTOMERS.CUSTOMERID = ORDERS.CUSTOMERID
HAVING
COUNT ( ORDERID ) >= 10 )
AS ORDERS
FROM
CUSTOMERS
WHERE
COUNTRY LIKE 'Germany'
OR COUNTRY LIKE 'Brazil'
ORDER BY
ORDERS ASC;

SQL Query for counting number of orders per customer and Total Dollar amount

I have two tables
Order with columns:
OrderID,OrderDate,CID,EmployeeID
And OrderItem with columns:
OrderID,ItemID,Quantity,SalePrice
I need to return the CustomerID(CID), number of orders per customer, and each customers total amount for all orders.
So far I have two separate queries. One gives me the count of customer orders....
SELECT CID, Count(Order.OrderID) AS TotalOrders
FROM [Order]
Where CID = CID
GROUP BY CID
Order BY Count(Order.OrderID) DESC;
And the other gives me the total sales. I'm having trouble combining them...
SELECT CID, Sum(OrderItem.Quantity*OrderItem.SalePrice) AS TotalDollarAmount
FROM OrderItem, [Order]
WHERE OrderItem.OrderID = [Order].OrderID
GROUP BY CID
I'm doing this in Access 2010.
You would use COUNT(DISTINCT ...) in other SQL engines:
SELECT CID,
Count(DISTINCT O.OrderID) AS TotalOrders,
Sum(OI.Quantity*OI.SalePrice) AS TotalDollarAmount
FROM [Order] O
INNER JOIN [OrderItem] OI
ON O.OrderID = OI.OrderID
GROUP BY CID
Order BY Count(DISTINCT O.OrderID) DESC
Which Access unfortunately does not support. Instead you can first get the Order dollar amounts and then join them before figuring the order counts:
SELECT CID,
COUNT(Orders.OrderID) AS TotalOrders,
SUM(OrderAmounts.DollarAmount) AS TotalDollarAmount
FROM [Orders]
INNER JOIN (SELECT OrderID, Sum(Quantity*SalePrice) AS DollarAmount
FROM OrderItems GROUP BY OrderID) AS OrderAmounts
ON Orders.OrderID = OrderAmounts.OrderID
GROUP BY CID
ORDER BY Count(Orders.OrderID) DESC
If you need to include Customers that have orders with no items (unusual but possible), change INNER JOIN to LEFT OUTER JOIN.
Create a query which uses your 2 existing queries as subqueriers, and join the 2 subqueries on CID. Define your ORDER BY in the parent query instead of in a subquery.
SELECT
sub1.CID,
sub1.TotalOrders,
sub2.TotalDollarAmount
FROM
(
SELECT
CID,
Count(Order.OrderID) AS TotalOrders
FROM [Order]
GROUP BY CID
) AS sub1
INNER JOIN
(
SELECT
CID,
Sum(OrderItem.Quantity*OrderItem.SalePrice)
AS TotalDollarAmount
FROM OrderItem INNER JOIN [Order]
ON OrderItem.OrderID = [Order].OrderID
GROUP BY CID
) AS sub2
ON sub1.CID = sub2.CID
ORDER BY sub1.TotalOrders DESC;