Aggregate Function Confusion - sql-server

I have a table with a list of products, schema is:
Product, Warehouse, Supplier, Order Quantity
What I want to do is for each supplier, select the warehouse that has the most order quantity.
Table Data:
Cornflakes, WH1, Kellogs, 10
Cornflakes, WH2, Kellogs, 5
Cornflakes, WH3, Kellogs, 0
Crunchy, WH1, Cadbury, 20
Crunchy, WH2, Cadbury, 10
Mars, WH1, Cadbury. 56
Mars, WH4, Cadbury, 8
I think there is enough information here to provide easy answer, if there is not please ask me for clarification in a comment rather than downvote and I will edit question very quickly.
Sample Output:
Kellogs, WH1
Cadbury, WH1
Warehouse number will be this one because it has the most total quantity to order for every product under that supplier.

MS SQL 2008+
SELECT Supplier, Warehouse
FROM (
SELECT Warehouse, Supplier, rn=ROW_NUMBER() OVER (PARTITION BY Supplier ORDER BY SUM([Order Quantity]) DESC)
FROM t
GROUP BY Warehouse, Supplier
) tt
WHERE rn=1

Try this one :
select a.supplier,a.warehouse,a.max(Order Quantity) from
(select supplier,warehouse,sum(Order Quantity) as quantity from products
group by supplier,warehouse)a
group by a.supplier,a.warehouse

Related

min(count(*)) over... behavior?

I'm trying to understand the behavior of
select ..... ,MIN(count(*)) over (partition by hotelid)
VS
select ..... ,count(*) over (partition by hotelid)
Ok.
I have a list of hotels (1,2,3)
Each hotel has departments.
On each departments there are workers.
My Data looks like this :
select * from data
Ok. Looking at this query :
select hotelid,departmentid , cnt= count(*) over (partition by hotelid)
from data
group by hotelid, departmentid
ORDER BY hotelid
I can perfectly understand what's going on here. On that result set, partitioning by hotelId , we are counting visible rows.
But look what happens with this query :
select hotelid,departmentid , min_cnt = min(count(*)) over (partition by hotelid)
from data
group by hotelid, departmentid
ORDER BY hotelid
Question:
Where are those numbers came from? I don't understand how adding min caused that result? min of what?
Can someone please explain how's the calculation being made?
fiddle
The 2 statements are very different. The first query is counting the rows after the grouping and then application the PARTITION. So, for example, with hotel 1 there is 1 row returned (as all rows for Hotel 1 have the same department A as well) and so the COUNT(*) OVER (PARTITION BY hotelid) returns 1. Hotel 2, however, has 2 departments 'B' and 'C', and so hence returns 2.
For your second query, you firstly have the COUNT(*), which is not within the OVER clause. That means it counts all the rows within the GROUP BY specified in your query: GROUP BY hotelid, departmentid. For Hotel 1, there are 4 rows for department A, hence 4. Then you take the minimum of 4; which is unsurprisingly 4. For all the other hotels, they have at least 1 entry with only 1 row for a hotel and department and so returns 1.

Putting multiple ordered items in one record

I am trying to place all bought items of one order in one record. Something like this
OrderID Occupation Age Product Name 1 Product Name 2
300 Network Analyst 33 Switches Hp Laptop
For now, my records look like this
OrderID Occupation Age Product Name
300 Network Analyst 33 Switches
300 Network Analyst 33 Hp Laptop
Initially I have four tables. The Customer Table, Product Table, Order Table and Ordered Product Table.
I created a view of all the transactions, which basically looks like the second table shown above.
I want it to look like the first table above if possible.
Use conditional aggregation :
select OrderId, Occupation, Age,
max(case when Seq = 1 then Product end) [Product1],
max(case when Seq = 2 then Product end) [Product2]
from (select *,
row_number() over (partition by OrderId, Occupation, Age order by Product) Seq
from table t) t1
where Seq in (1,2)
group by OrderId, Occupation, Age;
However, this may fail if you are looking n number of product IF so, then you need to go with PIVOT with dynamic style.

Sum field(s) from one table in another table, summing from 3 different tables

I have an Access database with customer IDs. Each customer can have multiple orders and each order can be of a different type. I have three separate tables (Online, In-store, Payment Plan) for each order type with various amounts from each order, all are related to a customer ID. In one of the tables, there are two types of order types that amounts must be maintained separately withing the same table. I want to sum each order type in another table called Totals. I can successfully create a query to get the sums for each type based on the customer ID but I am not sure how to pull those values in my Totals table. The scenario below is repeated for multiple customers and each type is its own table---the payment plans are in a table together. I have historical data so I am limited to how I can manipulate as far as merging fields and what not.
Customer ID#: 1
Order Type: Online
Online Amount: $20.00
Order Type: Online
Online Amount: $40.00
Sum of Online Amount: $60.00
Order Type: In-store
Online Amount: $35.00
Order Type: In-store
Online Amount: $60.00
Sum of In-Store Amount: $95.00
Order Type: Payment Plan
Payment Plan 1 Amount: $30.00
Payment Plan 1 Amount: $23.00
Sum of Payment Plan 1 Amount: $53.00
Order Type: Payment Plan 2
Payment Plan 2 Amount: $35.00
Payment Plan 2 Amount: $30.00
Sum of Payment Plan 2 Amount: $65.00
In my Totals table I have a field for each type that sums the amount spent by each customer ID and then a field where all of their order types are summed into one overall total field.
I am learning as I go so any help/example is appreciated. Thank you.
Having separate tables for your different order types doesn't help. For a database it would be better to have a single table for all sales with a sale_type field.
You don't describe exactly what your tables look like, so I've had to make a couple of assumptions. If your tables contain an OrderType field then you can create a Union query to join all your sales together:
SELECT CustomerID
, OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [Payment Plan]
If you don't have an OrderType you can hard-code the values into the query:
SELECT CustomerID
, "Online" AS OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, "In-Store"
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, "Payment Plan"
, Amount
FROM [Payment Plan]
Note - The field name is declared for the OrderType in the first Select block. You could do it in each block, but Access only looks at the first.
Like all queries, the results come in table form and can be treated as such. So now we need to list the CustomerName (I'm assuming you have a Customers table), the OrderType and the sum of the amount for that Customer & OrderType.
SELECT CustomerName
, OrderType
, SUM(Amount)
FROM Customers INNER JOIN
(
SELECT CustomerID
, OrderType
, Amount
FROM Online
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [In-Store]
UNION ALL SELECT CustomerID
, OrderType
, Amount
FROM [Payment Plan]
) T1 ON Customers.CustomerID = T1.CustomerID
GROUP BY CustomerName
, OrderType
All sales in your three tables will have a customer within the customers table so we can use an INNER JOIN to return only records where the value appears in both tables (Customers table & result of query table).
The UNION QUERY is wrapped in brackets and given the name T1and joined to the Customers table on the CustomerID field.
We group all fields that aren't part of an aggregate function, so group on CustomerName and OrderType and sum the Amount field.
This is all you really need to do - let the query run each time you want the totals to get the most up to date values. There's shouldn't be a need to push the results to a Totals table as that will be out of date as soon as you make a new sale (or someone returns something).
If you really want to INSERT these figures into a Total table just add a first line to the SQL:
INSERT INTO Total (CustomerName, OrderType, Amount)
Here is a dirty workaround, though I think there might be a more direct solution to it.
You could create an output table (I broke it down to ID, Online, InStore and Total) and use DSum functions within an UPDATE query.
UPDATE tbl_Totals SET
Total_InStore = DSum("Amount", "tbl_InStore", "Customer_ID = " & Customer_ID),
Total_Online = DSum("Amount", "tbl_Online", "Customer_ID = " & Customer_ID),
Total = DSum("Amount", "tbl_InStore", "Customer_ID = " & Customer_ID) + DSum("Amount", "tbl_Online", "Customer_ID = " & Customer_ID)

How to construct an SQL query for finding which company has the most employees?

I have the following tables and I would like to find the company which has the most workers. I am fairly new to sql and I would like some help on constructing the query. Any briefing would be appreciated on which keywords to use or how to begin with writing the query. I would like to
“Find the company that has the most workers.”
worker(worker_name, city, street)
work for(worker_name, company_name, salary)
company(company_name, city)
manages( worker_name, manage_name)
this will get you the company with the most employees in it.
select top 1 company_name,
count(*) as nbr_of_employees
from work-for
group by company_name
order by 2 desc
For more detailed answer please add sample data to your question and expected result.
how it works:
the group by company_name will group all records with the same company_name togheter. Because of that the count(*) will give you the number of records in work-for for each group. (thus all workers for each company)
the order by 2 desc will make sure that the company-name with the most employees is on top of the lists
Finally, the top 1 in the select will only return the first record in that list

t sql sort by calculated column

I'm on T-SQL 2014 and try to order products by their price. Now here is the problem: the price is a calculated field. Eg. I have created a function which evaluates a number of pricing rules (maybe about 4 tables with each about 4,000,000 records combined with JOINs to fit to the current login) and returns the users price for the product. While this is OK if I just want to return the price for a limited number of products it is way to slow if I want to sort by this.
I was thinking about having an additional table like UserProductPrice which will get calculated in the background but this will obviously not always have the correct price in it as the rules etc. could change in between the calculation.
Any suggestion on how I could sort by the price would be most appreciated.
You could use the ROW_NUMBER() function and place this into a temp table:
SELECT
Product,
dbo.ufnPrice(Price) as Price,
ROW_NUMBER() OVER (PARTITION BY Product ORDER BY dbo.ufnPrice(Price) DESC) AS Ranking
INTO #Products
FROM dbo.Products
SELECT
Product,
Price,
FROM #Products
WHERE Ranking = 1
DROP TABLE #Products
Should give you what you need.

Resources