SQL Server - SELECT statement not returning results - sql

Using the AdventureWorks database, I have been given a question to "List the orders customer name, order status, date ordered, count of items on the order, and average quantity ordered where the count of items on the order is greater than 300". However, my below SELECT statement does not return any results... What am I doing wrong?
SELECT scpii.LastName + ', ' + scpii.FirstName AS 'Customer Name', ssoh.Status AS 'Order Status', ssoh.OrderDate AS 'Date Ordered', SUM (ssod.OrderQty) AS 'Count of Items', AVG (ssod.OrderQty) AS 'Average Quantity'
FROM Sales.CustomerPII scpii
INNER JOIN Sales.SalesOrderHeader ssoh
ON ssoh.CustomerID = scpii.CustomerID
INNER JOIN Sales.SalesOrderDetail ssod
ON ssod.SalesOrderID = ssoh.SalesOrderID
GROUP BY scpii.LastName, scpii.FirstName, ssoh.Status, ssoh.OrderDate, ssod.OrderQty
HAVING SUM(ssod.OrderQty) > 300;

You dont need to Group By on ProductID and Orderqty. If you do a groupping on them, you will be grouping it to a single order item level. So you will never be able to count more than 300
Count of items on order should really be sum of the Orderqty.
Try:
SELECT scpii.LastName + ', ' + scpii.FirstName AS 'Customer Name',
ssoh.Status AS 'Order Status',
ssoh.OrderDate AS 'Date Ordered',
SUM (ssod.OrderQty) AS 'Count of Items',
AVG (ssod.OrderQty) AS 'Average Quantity'
FROM Sales.CustomerPII scpii
INNER JOIN Sales.SalesOrderHeader ssoh
ON ssoh.CustomerID = scpii.CustomerID
INNER JOIN Sales.SalesOrderDetail ssod
ON ssod.SalesOrderID = ssoh.SalesOrderID
GROUP BY scpii.LastName,
scpii.FirstName,
ssoh.Status,
ssoh.OrderDate
HAVING SUM (ssod.OrderQty) > 300;

Related

I need help to solve this exercise with SQL Server

I'm working with AdventureWorks Database. And this is the schema of the Database (https://i.stack.imgur.com/iWJxh.gif).
The exercise statement:
Do a report for the last week with following details.
OrderDate
Sales Person Name
SalesID
Customer Person Name
Quantity of products selled
Quantity of distinct products selled
Total Amount of the sale
Credit Card type used for pay
If sales had a special offer
Paying attention to the following statements:
Take the last 7 days for which you have sales data.
Do not show sales that were paid with cards of the type "ColonialVoice".
Dates should be displayed in "DD/MM/YYYY" format.
The report be ordered by Date, descending.
There should not be two rows with the same sale id in the report.
I try with this code and the results that it gives me are only for some dates, and if you pay attention it only brings me the first day of each month only
SELECT
SOH.OrderDate AS 'Fecha_Venta',
PERSONASVendedor.FirstName + ' ' + PERSONASVendedor.LastName AS 'Nombre_Vendedor',
SOH.SalesOrderID AS 'ID_Venta',
PERSONASCliente.FirstName + ' ' + PERSONASCliente.LastName AS 'Nombre_Cliente',
SUM(SOD.OrderQty) AS 'Cantidad_Productos_Vendidos',
COUNT(DISTINCT SOD.ProductID) AS 'Productos_Distintos_Vendidos',
SUM(SOD.LineTotal) AS 'Monto_Total',
TARJETA.CardType AS 'Tarjeta',
CASE WHEN SOD.SpecialOfferID <> 1 THEN 'Si' ELSE 'No' END AS 'Ventas_Con_Ofertas'
FROM Sales.SalesOrderHeader SOH
INNER JOIN Sales.SalesPerson ON SOH.SalesPersonID = Sales.SalesPerson.BusinessEntityID
INNER JOIN Sales.Customer ON SOH.CustomerID = Sales.Customer.CustomerID
INNER JOIN Person.Person PERSONASVendedor ON Sales.SalesPerson.BusinessEntityID = PERSONASVendedor.BusinessEntityID
INNER JOIN Person.Person PERSONASCliente ON Sales.Customer.PersonID = PERSONASCliente.BusinessEntityID
INNER JOIN Sales.SalesOrderDetail SOD ON SOH.SalesOrderID = SOD.SalesOrderID
INNER JOIN Sales.CreditCard TARJETA ON SOH.CreditCardID = TARJETA.CreditCardID
WHERE TARJETA.CardType <> 'ColonialVoice'
GROUP BY SOH.OrderDate, SOH.SalesOrderID, PERSONASVendedor.FirstName, PERSONASVendedor.LastName, PERSONASCliente.FirstName, PERSONASCliente.LastName, TARJETA.CardType, SOD.SpecialOfferID
ORDER BY SOH.OrderDate DESC
How can I solve this problem?
I would be missing to do some statements too.
Results obtained

get no value when I run the query to this question

The assignment question is...
List the order's customer name, order status, date ordered, count of items on the order, and average quantity ordered where the count of items on the order is greater than 300.
I'm using Adventure Works 2019 for the assignment.
The answer I have been able to come up with is....
SELECT
LastName + ', ' + FirstName AS 'Customer Name',
ssoh.Status AS 'Order Status',
ssoh.OrderDate AS 'Date Order',
SUM(ssod.Orderqty) AS 'Count of Items',
AVG(ssod.Orderqty) AS 'Average Quantity'
FROM
Person.Person pp
JOIN Sales.SalesOrderHeader ssoh ON pp.BusinessEntityID = ssoh.CustomerID
JOIN Sales.SalesOrderDetail ssod on ssoh.SalesOrderID = ssod.SalesOrderid
GROUP BY
LastName + ', ' + FirstName,
ssoh.OrderDate,
ssoh.Status
HAVING
SUM(ssod.OrderQty) > 300
When I change the inner join to an outer join I get null values for the customer name. I doubled checked the "customerID" foreign key to make sure it the same as the primary key "BusinessEntityID" and get results. Any ideas would be greatly appreciated. Thanks
Based on having a quick look at the schema online (I don't have it installed), it's my understanding that you need to join Person.Person through Sales.Customer to Sales.SalesOrderHeader. So perhaps try the following:
FROM
Person.Person pp
JOIN Sales.Customer sc ON pp.BusinessEntityID= sc.PersonID
JOIN Sales.SalesOrderHeader ssoh ON sc.CustomerID= ssoh.CustomerID
JOIN Sales.SalesOrderDetail ssod on ssoh.SalesOrderID = ssod.SalesOrderid
First, grouping by LastName + ', ' + FirstName will provide you inaccurate results.
Because there are approx 380 names with duplications. Sample:
Second, Manachi is right about the join.
So, your final query should be like this:
WITH cte AS (
SELECT
BusinessEntityID AS CustomerId,
LastName + ', ' + FirstName AS 'Customer Name',
ssoh.Status AS 'Order Status',
ssoh.OrderDate AS 'Date Order',
SUM(ssod.Orderqty) AS 'Count of Items',
AVG(ssod.Orderqty) AS 'Average Quantity'
FROM
Person.Person pp
JOIN Sales.Customer c ON c.PersonID = pp.BusinessEntityID
JOIN Sales.SalesOrderHeader ssoh ON c.CustomerID = ssoh.CustomerID
JOIN Sales.SalesOrderDetail ssod on ssoh.SalesOrderID = ssod.SalesOrderid
GROUP BY
BusinessEntityID,
LastName + ', ' + FirstName,
ssoh.OrderDate,
ssoh.Status
HAVING
SUM(ssod.OrderQty) > 300
)
SELECT
[Customer Name],
[Order Status],
[Date Order],
[Count of Items],
[Average Quantity]
FROM cte

Aggregates with inner join issue

I am having issues getting the aggregate function to work with this AdventureWorks database example. I'm attempting to get shipping methods whose annual total due is greater than 5 million but when I uncomment number of employees and distinct number of employees, both total dues end up the same. Could anyone give me some help so I can understand what i need to do? I've tried CTE and over() but the aggregates didn't agree with me then. Thank you.
USE AdventureWorks2014
SELECT DISTINCT S.Name AS 'ShippingMethod',
dt.OrderYear AS 'OrderYear',
dt.[Total Due] AS 'Total Due',
dt.[Average Total Due] AS 'Average Total Due',
dt.[Number Of Employees] AS 'Number Of Employees',
dt.[Distinct Number of Employees] AS 'Distinct Number of Employees'
FROM Purchasing.ShipMethod AS S
INNER join
(SELECT
s.Name AS 'ShippingMethod',
YEAR(P.OrderDate) AS 'OrderYear',
SUM(p.TotalDue) AS 'Total Due',
AVG(p.TotalDue) AS 'Average Total Due',
COUNT(p.EmployeeID) AS 'Number Of Employees',
p.VendorID AS 'Distinct Number of Employees'
FROM Purchasing.PurchaseOrderHeader AS P
inner JOIN Purchasing.ShipMethod AS S
ON P.ShipMethodID = S.ShipMethodID --AND p.[Total Due]=p.[Average Total Due]
group by s.Name, p.OrderDate, p.VendorID --,p.EmployeeID --/*p.TotalDue,*/----,p.VendorID
-- having SUM(p.TotalDue) > 5000000
)
AS dt
ON S.Name = dt.ShippingMethod --AND dt.[Total Due]=dt.[Average Total Due]
WHERE dt.[Total Due] > 5000000 and dt.OrderYear = '2014'--dt.[Total Due] BETWEEN dt.OrderYear 5000000
ORDER BY dt.[Total Due] DESC, OrderYear --dt.[Total Due] DESC--YEAR(dt.OrderYear) DESC
what about that group by for orderyear? (group by s.Name, YEAR(P.OrderDate), p.VendorID)
SELECT
s.Name AS 'ShippingMethod',
YEAR(P.OrderDate) AS 'OrderYear',
SUM(p.TotalDue) AS 'Total Due',
AVG(p.TotalDue) AS 'Average Total Due',
COUNT(p.EmployeeID) AS 'Number Of Employees',
p.VendorID AS 'Distinct Number of Employees'
FROM Purchasing.PurchaseOrderHeader AS P
inner JOIN Purchasing.ShipMethod AS S
ON P.ShipMethodID = S.ShipMethodID --AND p.[Total Due]=p.[Average Total Due]
group by s.Name, YEAR(P.OrderDate), p.VendorID

Find Average Sales Amount Per Customer using AdventureWorks2012

I am following a tutorial using MS AdventureWorks2012 and I wanted to write a query to find average sales amount per customer (or in other words, Average Sales for each customer) using AdventureWorks2012. Below is my attempt and it doesn't run. What Am I doing wrong here ?
SELECT soh.CustomerID AS 'Customer ID'
,p.FirstName + ' ' + p.LastName AS 'Customer Name'
,AVG(soh.TotalDue) AS 'Average Sales Amount Per Customer'
FROM Sales.SalesOrderHeader AS soh
INNER JOIN Sales.Customer AS c ON c.CustomerID = soh.CustomerID
INNER JOIN Person.BusinessEntityContact AS bec ON bec.PersonID = c.PersonID
INNER JOIN Person.Person AS p ON p.BusinessEntityID = bec.BusinessEntityID
GROUP BY p.FirstName , p.LastName, soh.CustomerID;
Your query runs, it just returns an empty result set.
If you look at BusinessEntityContact, it relates a BusinessEntityID, which is a customer business, to a PersonID, who is a person that is the contact for the business. So if you change your query to this:
SELECT soh.CustomerID AS 'Customer ID', p.FirstName + ' ' + p.LastName AS 'Customer Name',
AVG(soh.TotalDue) AS 'Average Sales Amount Per Customer'
FROM Sales.SalesOrderHeader AS soh
INNER JOIN Sales.Customer AS c ON c.CustomerID = soh.CustomerID
INNER JOIN Person.BusinessEntityContact AS bec ON bec.PersonID = c.PersonID
INNER JOIN Person.Person AS p ON p.BusinessEntityID = bec.PersonID
GROUP BY p.FirstName , p.LastName, soh.CustomerID;
(note the third inner join)
You will get 635 rows.
In SQL single quote ' identifies a string. If you must to have spaces in your result column names then you can identify column names with double quotes " or preferably by wrapping the column name in square brackes.
SELECT
soh.CustomerID AS [Customer ID]
,p.FirstName + ' ' + p.LastName AS [Customer Name]
,AVG(soh.TotalDue) AS [Average Sales Amount Per Customer]
FROM Sales.SalesOrderHeader AS soh
INNER JOIN Sales.Customer AS c ON c.CustomerID = soh.CustomerID
INNER JOIN Person.BusinessEntityContact AS bec ON bec.PersonID = c.PersonID
INNER JOIN Person.Person AS p ON p.BusinessEntityID = bec.BusinessEntityID
GROUP BY p.FirstName , p.LastName, soh.CustomerID;
Otherwise your syntax looks okay to me

SQL Query SUM issue

I am writing a SQL query where i want to list down and calculate some data every thing looks to work fine but the only problem I am having is when i SUM values in a given column the final result is a overall total but i want this total only to be for a month of October.
The scenario is as followed i need to calculate a total amount of deposits made by costomers over the month of October with other information that works well its only the sum issue.
SQL:
SELECT customers.id AS 'Customer ID',
customers.firstname AS
'Customer First Name',
customers.lastname AS 'Customer Last Name'
,
users.firstname AS
'Employee First Name',
users.lastname AS 'Employee Last Name'
,
positions.currency AS 'Currency',
Sum(customer_deposits.amount) AS 'Total Deposits',
Sum(positions.status) AS 'Total Bets',
Sum(customer_total_statistics.totalbonusdeposits) AS 'Total Bonuses',
positions.date AS 'Date'
FROM customers
LEFT JOIN customer_deposits
ON customers.id = customer_deposits.customerid
LEFT JOIN users
ON customers.employeeinchargeid = users.id
LEFT JOIN positions
ON customers.id = positions.customerid
LEFT JOIN customer_total_statistics
ON customers.id = customer_total_statistics.customerid
WHERE customer_deposits.status = 'approved'
AND positions.status = 'won'
AND positions.date BETWEEN '2013-10-01' AND '2013-11-01'
AND customers.isdemo = '0'
GROUP BY customers.id
ORDER BY customers.id
Well, you don't filter your customer_deposits at all, so the sum over customer_deposits.amount will of course give you the sum of all the deposits. You'll have to add another where to filter customer_deposits by date as well, not just positions.
It looks like you have multiple 1-n relationships so your joins are creating cartesian products. So if you had a customer with 2 deposits and 2 positions:
Positions customer_deposits
CustomerID | Amount CustomerID | Amount
1 | 10 1 | 30
1 | 20 1 | 40
When you do this join:
SELECT c.ID, cd.Amount AS DepositAmount, p.Amount AS PositionAmount
FROM Customers c
INNER JOIN customer_deposits cd
ON c.ID = cd.CustomerID
INNER JOIN Positions p
ON c.ID = p.CustomerID
You end up with 4 rows with all combinations of deposit amount and position amount:
ID DepositAmount PositionAmount
1 10 30
1 10 40
1 20 30
1 20 40
So if you sum this up you end up with incorrect sums because rows are duplicated. You need to move your SUMs to subqueries:
SELECT customers.id AS 'Customer ID',
customers.firstname AS 'Customer First Name',
customers.lastname AS 'Customer Last Name',
users.firstname AS 'Employee First Name',
users.lastname AS 'Employee Last Name',
positions.currency AS 'Currency',
cd.amount AS 'Total Deposits',
P.status AS 'Total Bets',
cs.totalbonusdeposits AS 'Total Bonuses',
positions.date AS 'Date'
FROM customers
INNER JOIN
( SELECT CustomerID, SUM(Amount) AS Amount
FROM customer_deposits
WHERE customer_deposits.status = 'approved'
GROUP BY CustomerID
) cd
ON customers.id = cd.customerid
LEFT JOIN users
ON customers.employeeinchargeid = users.id
INNER JOIN
( SELECT CustomerID, Date, SUM(Status) AS Status
FROM positions
WHERE positions.status = 'won'
AND positions.date BETWEEN '2013-10-01' AND '2013-11-01'
GROUP BY CustomerID, Date
) P
ON customers.id = positions.customerid
LEFT JOIN
( SELECT CustomerID, SUM(totalbonusdeposits) AS totalbonusdeposits
FROM customer_total_statistics
GROUP BY CustomerID
) cs
ON customers.id = customer_total_statistics.customerid
WHERE customers.isdemo = '0';
Note, you have used fields in the where clause for left joined tables which effectively turns them into an inner join, e.g.
positions.status = 'won'
If there is no match in positions, the status will be NULL, and NULL = 'won' evaluates to NULL (not true) so it will exclude all rows where there is no match in position. As such I have changed your LEFT JOIN's to INNER.