Aggregates with inner join issue - sql

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

Related

Total sum value out of Group By

I have a drugstore chain database. In the script below I'm trying to print out
store
category
sales of particular category in the particular store
total sales of the particular category in all the stores
My code:
SELECT
s.store_name AS [Drug Store],
g.group_name AS [Category],
SUM(f.quantity) AS [Sales pcs.]
-- (SELECT SUM(quantity) AS [Total sales] GROUP BY g.group_name)
FROM
[dbo].[fct_cheque] AS f
INNER JOIN
[dim_stores] AS s ON s.store_id = f.store_id
INNER JOIN
dim_goods AS g ON g.good_id = f.good_id
WHERE
date_id BETWEEN '20170601' AND '20170630'
GROUP BY
s.store_name, g.group_name
How to handle the last one?
You may use SUM() as an analytic function, for the second sum which is commented out in your question:
SELECT s.store_name AS [Drug Store],
g.group_name AS [Category],
SUM(f.quantity) AS [Sales pcs.],
SUM(SUM(f.quantity)) OVER (PARTITION BY g.group_name) AS [Total sales]
FROM [dbo].[fct_cheque] AS f
INNER JOIN [dim_stores] AS s ON s.store_id = f.store_id
INNER JOIN dim_goods AS g ON g.good_id = f.good_id
WHERE date_id BETWEEN '20170601' AND '20170630'
GROUP BY s.store_name, g.group_name;

SQL DML how to combine value from other row after using count, sql server

this is my code:
select CustomerName, count(td.bikeid) as [Total Transactions], sum(quantity) as [Total Bikes Bought],
replace(customerphone, '0', '+62') as [Customer Phone]
from MsCustomer mc join TransactionHeader th
on mc.CustomerID = th.CustomerID join TransactionDetail td
on th.TransactionID = td.TransactionID join MsBike mb
on td.BikeID = mb.BikeID
group by td.BikeID, td.TransactionID, CustomerName, Quantity, CustomerPhone
having sum(Quantity) > 5 and count(th.transactionid) between 2 and 5
and the result is this
How can I make it so that the total transactions and bikes bought of the same customername got summed up, for example of the result I want:
(cendana, 2, 16, +6283859786138)
Your GROUP BY clause seems the culprit here. Usually, all the ungrouped columns from SELECT list will go into GROUP BY clause but you have multiple columns in GROUP BY clause without using them in SELECT list. Using those unnecessary columns in GROUP BY clasue is causing this issue. Just get rid of those columns, And you probably get your result -
SELECT CustomerName,
COUNT(td.bikeid) AS [Total Transactions],
SUM(quantity) AS [Total Bikes Bought],
REPLACE(customerphone, '0', '+62') AS [Customer Phone]
FROM MsCustomer mc
JOIN TransactionHeader th ON mc.CustomerID = th.CustomerID
JOIN TransactionDetail td ON th.TransactionID = td.TransactionID
JOIN MsBike mb ON td.BikeID = mb.BikeID
GROUP BY CustomerName, CustomerPhone
HAVING SUM(Quantity) > 5
AND COUNT(th.transactionid) BETWEEN 2 AND 5;

SQL Server - SELECT statement not returning results

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;

How to display customer name for every transaction with total price is higher than average price?

I want to display customer name if the total price is higher than the average price from every transaction. But the error message is "Column 'x.average' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause." and I don't know where the problems are.
Here's my code
SELECT c.CustomerId,
hs.TransactionId,
c.CustomerName,
SUM(t.Price) AS [Total Price]
FROM MsCustomer c JOIN HeaderSalonServices hs
ON c.CustomerId = hs.CustomerId
JOIN DetailSalonServices ds
ON ds.TransactionId = hs.TransactionId
JOIN MsTreatment t
ON t.TreatmentId = ds.TreatmentId,
(SELECT AVG(Price) AS average
FROM MsTreatment) AS x
GROUP BY c.CustomerId, hs.TransactionId, c.CustomerName
HAVING SUM(t.Price) > average
Try moving your subquery to the HAVING clause:
SELECT c.CustomerId,
hs.TransactionId,
c.CustomerName,
SUM(t.Price) AS [Total Price]
FROM MsCustomer c JOIN HeaderSalonServices hs
ON c.CustomerId = hs.CustomerId
JOIN DetailSalonServices ds
ON ds.TransactionId = hs.TransactionId
JOIN MsTreatment t
ON t.TreatmentId = ds.TreatmentId
GROUP BY c.CustomerId, hs.TransactionId, c.CustomerName
HAVING SUM(t.Price) > (SELECT AVG(Price) AS average FROM MsTreatment)

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.