Subquery, SQL Group By - sql

I`m following and example give in Coursera course SQL for Data Science, this is the example:
Select customer_name
,customer_state
(Select Count (*) AS orders
FROM Orders
Where Orders.customer_id = Customer.customer_id) AS orders
From customers
Order By Customer_name
So I try to apply the same logic to my Chinook DB using this query:
Select FirstName
,State
(Select Count (*) As invoices
From invoices
Where invoices.CustomerId = customers.CustomerId) As Orders
From Customers
Order by Firstname
But it seems like I`m making a mistake as SQLite wont even let me run it Do you have any idea why?

Missing comma before subquery.
so the syntax will be error.
Select customer_name
,customer_state
,(Select Count (*) AS orders
FROM Orders
Where Orders.customer_id = Customer.customer_id) AS orders
From customers
Order By Customer_name

Related

SUBSELECT (SQL)

I have to tables. The first table (customers) shows data about the customers (id, firstname, lastname). The second table shows data about the orders (timestamp and customer id). So, i wanted to see the last order by a customer in my table "customers" and did a SUBSELECT and it worked.
SELECT id,firstname, lastname,
(SELECT timestamp FROM orders
WHERE customers.id = orders.customer_id
ORDER BY timestamp DESC LIMIT 1) AS last_order
FROM customers
WHERE (SELECT timestamp FROM orders
WHERE customers.id = orders.customer_id) IS NOT NULL
But, there are some customers who never ordered something and so is no value in the column "last_order". I am trying to filter these customers out with another SUBSELECT after the WHERE but i am failing. Can somebody help me?
The problem is with the second sub-query, it may return more than one value (one customer may have multiple orders); it should return only one value, so you may limit it by 1 as the following:
WHERE (SELECT timestamp FROM orders
WHERE customers.id = orders.customer_id Limit 1) IS NOT NULL
Another approach is to use Exists as the following:
SELECT id,firstname, lastname,
(SELECT timestamp_ FROM orders
WHERE customers.id = orders.customer_id
ORDER BY timestamp_ DESC LIMIT 1) AS last_order
FROM customers
WHERE exists (SELECT 1 FROM orders
WHERE customers.id = orders.customer_id);
Also, you can achieve the required result with a simple Join query as the following:
Select C.id,C.firstname, C.lastname, Max(O.timestamp_) AS last_order
From customers C
join orders O on
C.id=O.customer_id
Group By C.id,C.firstname, C.lastname
See a demo from db-fiddle.

Find customer who bought least on W3schools SQL

I'm new to SQL Server and I'm trying to do some exercises. I want to find customers who bought least on W3schools database. My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
Here is my query:
SELECT COUNT(OrderID), CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(CustomerID) ASC
HAVING COUNT(OrderID) = '1'
When I ran this query, message says "Syntax error near "Having". What happened with my query?
Please help me to figure out.
My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
As #thorsten-kettner lamented:
You say in your explanation that you join and then show the customer
name. Your query does neither of the two things...
Furthermore, your question has severe grammatical errors making it hard to decipher.
I want to find customers who bought least on W3schools database.
Nonetheless,
The Try-SQL Editor at w3schools.com
To get the list of customers who have at least 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY C.CustomerName
To get the list of customers who have exactly 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
HAVING COUNT(O.OrderID) = 1
ORDER BY C.CustomerName
To get the customer who made the least number of orders:
Including the ones who made no order. Use JOIN instead of LEFT JOIN if you only want to consider the ones who made at least one order.
You can remove LIMIT 1 to get the whole list sorted by the number of orders placed.
SELECT C.CustomerName, COUNT(O.OrderID) FROM [Customers] AS C
LEFT JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY COUNT(O.OrderID), C.CustomerName
LIMIT 1;
Addendum
As commented by #sticky-bit ,
The ORDER BY clause has to come after the HAVING clause.
You want a TOP 1 WITH TIES query, something like this:
SELECT TOP 1 WITH TIES CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(OrderID);
In case you are using MySQL, try the following version:
SELECT CustomerID
FROM Orders
GROUP BY CustomerID
HAVING COUNT(OrderID) = (
SELECT COUNT(OrderID)
FROM ORDERS
GROUP BY CustomerID
ORDER BY COUNT(OrderID)
LIMIT 1
);

Query table columns from another table using the foreign key

I am trying to get customer email and phonenumber in orders table when I have the order id.
The structure of the schema is below with customer id in orders table:
orders
id
date
item
refid
customerFk
customers
id
name
email
phonenumber
when I try to retrieve the customers phonenumber or email table from the order refId in SQL Server using
select
from order a
where a.custtomerFK.email
I get this error
Cannot call method on bigints
Please assist with the proper query.
The proper syntax is:
SELECT o.date, o.item, o.refid c.Name, c.email, c.phonenumber
FROM orders o
LEFT JOIN customers c ON o.customerFk = c.id
ORDER BY o.date, o.item, c.name
You can use this if you have customers for each order
SELECT orders.date, orders.item, orders.refid
, customers.Name, customers.email, customers.phonenumber
FROM orders
INNER JOIN customers ON orders.customerFk = customers.id

Sql query to display records that appear more than once in a table

I have two tables, Customer with columns CustomerID, FirstName, Address and Purchases with columns PurchaseID, Qty, CustomersID.
I want to create a query that will display FirstName(s) that have bought more than two products, product quantity is represented by Qty.
I can't seem to figure this out - I've just started with T-SQL
You could sum the purchases and use a having clause to filter those you're interested in. You can then use the in operator to query only the customer names that fit these IDs:
SELECT FirstName
FROM Customer
WHERE CustomerID IN (SELECT CustomerID
FROM Purchases
GROUP BY CustomerID
HAVING SUM(Qty) > 2)
Please try this, it should work for you, according to your question.
Select MIN(C.FirstName) FirstName from Customer C INNER JOIN Purchases P ON C.CustomerID=P.CustomersID Group by P.CustomersID Having SUM(P.Qty) >2
Please try this:
select c.FirstName,p.Qty
from Customer as c
join Purchase as p
on c.CustomerID = p.CustomerID
where CustomerID in (select CustomerID from Purchases group by CustomerID having count(CustomerID)>2);
SELECT
c.FirstName
FROM
Customer c
INNER JOIN Purchases p
ON c.CustomerId = p.CustomerId
GROUP BY
c.FirstName
HAVING
SUM(p.Qty) > 2
While the IN suggestions would work they are kind of overkill and more than likely less performant than a straight up join with aggregation. The trick is the HAVING Clause by using it you can limit your result to the names you want. Here is a link to learn more about IN vs. Exists vs JOIN (NOT IN vs NOT EXISTS)
There are dozens of ways of doing this and to introduce you to Window Functions and common table expressions which are way over kill for this simplified example but are invaluable in your toolset as your queries continue to get more complex:
;WITH cte AS (
SELECT DISTINCT
c.FirstName
,SUM(p.Qty) OVER (PARTITION BY c.CustomerId) as SumOfQty
FROM
Customer c
INNER JOIN Purchases p
ON c.CustomerId = p.CustomerId
)
SELECT *
FROM
cte
WHERE
SumOfQty > 2

Select all orders by one customer

I have three tables, orders, orders_details and customers. I need to select orders by one customer for the orders table so I did this
orders columns:
id
customer_id
created
vat
discount
amount
paid
orders_details columns:
id
order_id
cost
qty
product
The SQL I used
SELECT
orders.*,
SUM(orders_details.qty*orders_details.cost) as amount,
SUM(orders_details.qty) AS qty
FROM
orders,
orders_details,
customers
WHERE
orders.customer_id = customers.id
AND orders_details.order_id = orders.id
AND orders.customer_id = 1
but I am getting a wrong qty of 30 instead of 20 and the amount is wrong
If you want to aggregate per order you need a GROUP BY clause. Also you should use proper JOIN syntax, and might consider using aliases to make the query more compact.
SELECT
o.*,
SUM(od.qty * od.cost) AS amount,
SUM(od.qty) AS qty
FROM orders o
INNER JOIN orders_details od ON od.order_id = o.id
INNER JOIN customers c ON o.customer_id = c.id -- not used, might be excluded
WHERE o.customer_id =1
GROUP BY o.id
Depending on what database system you are using you might need to include all columns referenced in o.* in the GROUP BY:
GROUP BY o.id, o.customer_id, o.created, o.vat, o.discount, o.amount, o.paid
Last note: as you don't seem to use any data from the customers table you probably could exclude that table altogether.
You're missing a GROUP BY clause which I'm guessing should be on orders.id.