SQL Aggregate function issues using DISTINCT function - sql-server

I'm needing help with a question that I've been racking my brain on for two days now (Almost), on this assignment. I'm still pretty new to SQL and I'm just struggling.
I DO NOT WANT THE ANSWER!! I'm just looking for help getting going in the right direction.
Here is the question:
Write a SELECT statement that answers this question: Which customers have ordered more than one product? Return these columns:
The email address from the Customers table
The count of distinct products from the customer’s orders
Here is what I have so far:
SELECT Customers.CustomerID,
Count(DISTINCT ProductID) AS ProductsCount
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
JOIN Products
ON Products.ProductID = OrderItems.ProductID
GROUP BY Customers.CustomerID,
Orders.CustomerID
But I keep getting this error:
Msg 4104, Level 16, State 1, Line 2
The multi-part identifier "OrderItems.ProductID" could not be bound.
The structure of the three tables in play here is.
The Customer table has an Emailaddress and CustomerID column.
The Orders table has CustomerID and OrderID columns.
The Products table has ProductID column.
The OrderItems table has OrderID, ProductID, and Quantity columns.
Any Help would be really really helpful!
Thanks!

Fix the syntax as suggested by joining to the OrderItems table and in order to look for something more than once, you need to use group by field1, field2, etc. having count(field) > 1. You are almost there.

You are almost there :-)
You forgot to join OrderItems.
You don't need the table Products in this query (you don't want to see anything from that table; you get the product count from OrderItems).
To limit by aggregates (as by the number of products here) use HAVING.
To group by Orders.CustomerID is superfluous, as it equals Customers.CustomerID.

Here is a tip to find the answer,
find the orders which has has more than one item in OrderItems
table by using having clause with Count() aggregate and Group by orderID.
so from the first step you will have the orders that have more than
one item and count of products in every order. next join the first step result with
order table to get the customerid.
next join the second step result with customers table to get the
customers information who bought more than one one product in single
order with count.

Related

How do I query three related tables?

I'm new to databases and I'm having a hard time figuring this out. Any assistance would be greatly appreciated
Deliveries Table
-- ID (PK)
-- DriverID (FK to Drivers Table)
Drivers Table
-- ID (PK)
-- LocationID (FK to Locations Table)
Locations Table
-- ID (PK)
-- RestaurantID (FK to Restaurants Table)
Restaurant Table
--ID (PK)
A Restaurant can have multiple locations (1 to many). A location can have multiple drivers (1 to many). a Driver can have multiple deliveries (1 to many). This design is supposed to break things out in 3rd normal form. So if I want to go to the deliveries table and get all of the deliveries associated with a particular restaurant, how would I query or do a join for that? Would I have to add a second foreign key to Deliveries that directly references the Restaurant table? I think after I see the query I can figure out what is going on. Thx
You can use left or right outer join to make a combined table and then you can easily query it, or else you can use a query with multiple sub-queries inside it to attain the required result without using join. Here is an example on how to use sub-query for your use-case.
SELECT ID FROM Deliveries De
WHERE De."DriverID" IN (SELECT ID FROM Drivers Dr
WHERE Dr. "LocationID" IN (SELECT ID FROM Locations L
WHERE L. "RestaurantID" IN (SELECT ID FROM Restaurant)))
I hope this solves your issue without using join statement.
You can use inner join or union depending on what you want to achieve. Example:
SELECT a."articleId" AS id, a.title, a."articleImage" AS "articleImage/url", c.category AS "category/public_id", a."createdOn", concat("firstName", ' ', "lastName") AS author
FROM articles a
INNER JOIN users u ON a."userId" = u."userId"
INNER JOIN categories c ON a."categoryId" = c."categoryId"
UNION
SELECT g."gifId" AS id, g.title, g."imageUrl" AS "articleImage/url", g.public_id AS "category/public_id", g."createdOn", concat("firstName", ' ', "lastName") AS author
FROM gifs g
INNER JOIN users u ON g."userId" = u."userId"
ORDER BY "createdOn" DESC
You can say how you want to get the results for more detailed query.
If I understand what you want to do then it maybe like this,
1st you have to join all those table to get corresponding result you want,
the join condition will be
select <your desire column name>
from Restaurant A,Locations B,Drivers C,Deliveries D
where A.ID = B.RestaurantID
and B.ID = C.LocationID
and C.ID = D.DriverID
Hope this is helpful, fell free to say anything.

SQLite - Return 0 if null

I have an assignment in Database Management Systems in which I have to write queries for given problems.
I have 4 problems, of which I solved 3 and stuck with the last one.
Details:
Using version 1.4 of the Chinook Database
(https://chinookdatabase.codeplex.com/).
SQLite DB Browser
Chinook Sqlite AutoIncrementPKs.sqlite file​ in the directory with Chinook files is the database I am working on
Problem Statement:
Write a query to generate a ranked list of employees based upon the amount of money brought in via customer invoices for which they were the support representative. The result set (see figure below) should have the following fields (in order) for all employees (even those that did not support any customers): ID (e_id), first name (e_first name), last name (e_last_name), title (e_title), and invoice total (total_invoices). The rows should be sorted by the invoice total (greatest first), then by last name (alphabetically), then first name (alphabetically). The invoice total should be preceded by a dollar sign ($) and have two digits after the decimal point (rounded, as appropriate); in the case of employees without any invoices, you should output a $0.00, not NULL. You may find it useful to look at the IFNULL, ROUND, and PRINTF functions of SQLite.
Desired Output:
My Query:
Select Employee.EmployeeId as e_id,
Employee.FirstName as e_first_name,
Employee.LastName as e_last_name,
Employee.Title as e_title,
'$' || printf("%.2f", Sum(Invoice.Total)) as total_invoices
From Invoice Inner Join Customer On Customer.CustomerId = Invoice.CustomerId
Inner Join Employee On Employee.EmployeeId = Customer.SupportRepId
Group by Employee.EmployeeId
Having Invoice.CustomerId in
(Select Customer.CustomerId From Customer
Where Customer.SupportRepId in
(Select Employee.EmployeeId From Employee Inner Join Customer On Employee.EmployeeId = Customer.SupportRepId)
)
order by sum(Invoice.Total) desc
My Output:
As you can see, the first three rows are correct but the later rows are not printed because employees don't have any invoices and hence EmployeeID is null.
How do I print the rows in this condition?
I tried with Coalesce and ifnull functions but I can't get them to work.
I'd really appreciate if someone can modify my query to get matching solutions.
Thanks!
P.S: This is the schema of Chinook Database
It often happens that it is simpler to use subqueries:
SELECT EmployeeId,
FirstMame,
LastName,
Title,
(SELECT printf("...", ifnull(sum(Total), 0))
FROM Invoice
JOIN Customer USING (CustomerId)
WHERE Customer.SupportRepId = Employee.EmployeeId
) AS total_invoices
FROM Employee
ORDER BY total_invoices DESC;
(The inner join could be replaced with a subquery, too.)
But it's possible that you are supposed to show that you have learned about outer joins, which generate a fake row containing NULL values if a matching row is not found:
...
FROM Employee
LEFT JOIN Customer ON Employee.EmployeeId = Customer.SupportRepId
LEFT JOIN Invoice USING (CustomerID)
...
And if you want to be a smartass, replace ifnull(sum(...), 0) with total(...).

Removing Duplicated Data after Joining Tables

I've been stuck on this query since a while and don't know how to go forward. The problem is when joining multiple tables: I noticed that the numeric data does not match the numeric data that I expect. This is because for each record in the table with fewer records, the join takes all of the corresponding records from the bigger table.
For example, suppose you have the following tables. The table with fewer records, Available Fruits, has one record for each A, B, C, D, and E. The table with more records, Sales Today, has multiple records each for A, B, C, D, and E.
Then suppose you use an JOIN to combine the two tables above.
SELECT A.*, B.*
FROM [Available Fruits] A
JOIN [Sales Today] B
ON A.[Fruit ID]=B.[Fruit ID]
The result is the table below. Notice that the rows from the Available Fruits table are duplicated for every instance the corresponding ID appears on the Sales Today table. i.e, If you place the Inventory and Fruit fields into a new table, this joined table causes the inventory of apples to appear as 375 instead of the expected 75, as shown in the following image.
Unfortunately I still don't have enough points to post images.
EDIT: So what I´d like to do in SQL is to somehow be able to roll up the "Sales Today" table to the "Available fruits" granularity level so it doesn't get duplicated OR somehow calculate the distribution of Inventory sold per A,B,C,D,E so I can Join the two tables without duplicate what I've explained with the Inventory field.
I really appreciate all your help guys.
You haven't actually posted what you want it to look like. Try Something like this (I am not in a position to try it right now and I have never done group by on joined tables before)
SELECT A.[Fruit ID], A.Fruit, sum(B.[Fruits Sold])
from [Available Fruits] A
left outer join [Sales Today] B on A.[Fruit ID] = B.[Fruit ID]
group by A.[Fruit ID], A.[Fruit]

SQL: Summing columns with a similar column in common

I'm extremely new to SQL Sever and so I apologize if the question is worded strange. I am doing a homework assignment, and this is the question:
"A manager wants to know the email address, number or orders, and the total amount of purchases made by each customer. Create a summary query that returns these three items for each customer that has orders."
I have all of the data queried, the problem is when I pull data from each customer, it will show the quantity of items per order, and I need the items to be pooled together into one column. This is my query thus far (again, total noob, please excuse any poor syntax, etc.)
SELECT EmailAddress,
ItemPrice - DiscountAmount * Quantity AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers
JOIN Orders ON Customers.CustomerID = Orders.CustomerID
JOIN OrderItems ON Orders.OrderID = OrderItems.OrderID
GROUP BY Orders.CustomerID,
OrderItems.ItemPrice, OrderItems.DiscountAmount,
OrderItems.Quantity,
Customers.EmailAddress;
The following is a small bit of the result set that I get:
Email Address OrderTotal OrderQty
allan.sherwood#yahoo.com 253.15 2
allan.sherwood#yahoo.com 839.30 2
allan.sherwood#yahoo.com 1208.16 2
barryz#gmail.com 303.79 4
christineb#solarone.com 479.60 2
david.goldstein#hotmail.com 299.00 2
david.goldstein#hotmail.com 489.30 1
david.goldstein#hotmail.com 479.60 1
So as you can see, I have several orders I need to smoosh together into one single row per e-mail, I have looked and looked for an answer but the only thing I can find is how to find duplicates and ignore them, not combine their data. Any help is extremely appreciate, thanks so much for taking the time to read this :) If my question doesn't make sense please let me know so I can clear up any bad wording I may have used!
Just do GROUP BY CustomerID, EmailAddress:
SELECT
c.EmailAddress,
SUM((i.ItemPrice - i.DiscountAmount) * Quantity) AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers c
INNER JOIN Orders o
ON c.CustomerID = o.CustomerID
INNER JOIN OrderItems i
ON o.OrderID = i.OrderID
GROUP BY
c.CustomerID, c.EmailAddress
Additional note: Use aliases for your tables
You need to change your formula and remove columns that you dont want to group by from select query..
for example your query should be something like this
SELECT EmailAddress,
--do your aggregation here
blah AS TotalPurchaseAmount,
COUNT(*) AS OrderQty
FROM Customers
JOIN Orders ON Customers.CustomerID = Orders.CustomerID
JOIN OrderItems ON Orders.OrderID = OrderItems.OrderID
GROUP BY Orders.CustomerID,
Customers.EmailAddress;

Unable to understand the SQL code

I am finding it difficult to understand the code below. Can you give me a logical flow of how the code works ?
The question -
suppose you want to display the total number of orders placed by every customer in your Customers table. Orders are stored in the Orders table along with the appropriate customer ID.
The steps -
retrieve the list of customers from the customers table.
for each customer retrieved, count the number of associated orders in the Orders table.
The solution -
SELECT cust_name, cust_state,
(SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id
)
AS order_nos
FROM Customers
ORDER BY cust_name
I am unable to understand the count(*) part inside the brackets. Please help me to figure it out.
Thanks.
It's just counting the number of rows. In this case, that's the number of orders per customer. The alternative COUNT(column_name) gives you the number of rows where column_name isn't null.
Equivalent without the sub-query (using a group instead):
SELECT cust_name, cust_state, COUNT(orders.cust_id) order_nos
FROM Customers
LEFT OUTER JOIN Orders on Customers.cust_id = Orders.cust_id
GROUP BY cust_name, cust_state
ORDER BY cust_name
It's called a correlated subquery. Essentially, for each customer, you're going to get a count of how many orders that customer has. The "magic" is in the WHERE Orders.cust_id = Customers.cust_id clause in the subquery. That's the part that correlates this result to your main query. It's saying "take the cust_id from the main query and now find the count of orders where the cust_id is that cust_id".

Resources