SQL - Display the minimum value of an average price - sql

My database contains a list of products and finishes. I have been able to successfully average the price of each finish option, but I only want to display the lowest priced option.
Here is a sample of my data.
Table 1 - product_t
ProductID ProductLineID ProductDescription ProductFinish ProductStandardPrice ProductOnHand
1 1 "Cherry End Table" Cherry 175.00 0
2 1 "Birch Coffee Tables" Birch 200.00 0
3 1 "Oak Computer Desk" Oak 750.00 0
4 1 "Entertainment Center" Cherry 1650.00 0
This query results in a list of each available product finish and the average price of an item that has the finish.
SELECT ProductFinish, AVG(ProductStandardPrice) as AveragePrice
FROM product_t
WHERE ProductFinish IS NOT NULL
GROUP BY ProductFinish;
However, I only want to display the lowest price that results from this query. I attempted this query, but it will not execute.
SELECT ProductFinish, MIN (AVG(ProductStandardPrice)) as AveragePrice
FROM product_t
WHERE ProductFinish IS NOT NULL
GROUP BY ProductFinish;
Thanks in advance for any help. It is much appreciated.

A typical way to get the lowest value is to use order by and some sort of limit on the number of rows. In ANSI standard SQL, this would be:
SELECT ProductFinish, AVG(ProductStandardPrice) as AveragePrice
FROM product_t
WHERE ProductFinish IS NOT NULL
GROUP BY ProductFinish;
ORDER BY AveragePrice ASC
FETCH FIRST 1 ROW ONLY;
Note that some databases using LIMIT 1 or TOP 1 instead of FETCH FIRST 1 ROW ONLY. Also, this version only fetches one record with the lowest price. If there are duplicate minimums, an arbitrary value is chosen.

Related

SQL finding the sum of subrange of values

I am working on a conversion script in Access VBA where i need a query to change the column requested quantity to contain the sum of the delivered quantity per order line. Right now it looks like this:
ordernumber orderlinenumber requestedquantity deliveredquantity
123456 1000 1 1
123456 1001 2 2
123456 2000 50 50
123456 3000 10 10
So for order number 123456 line number 1000 & 1001 requested quantity should become 3.
Basically what i need is an update query that goes through order line 1000-1999, calculates the sum of the delivered quantity and sets it for the requested quantity. I tried a few different constructions using the SUM clause but i can not seem to find a way to loop through the order lines.
Hmmm . . . You can use aggregation
select ordernumber, min(orderlinenumber), sum(requestedquantity), sum(deliveredquantity)
from t
group by ordernumber, orderlinenumber \ 1000
The backwards slant is MS-Access-speak for integer division.

SQL statement, check if other rows have the same value

I have a SQL statement that imports my product inventory from a Access.MDB file. The select statement is below. (well a portion of it)
SELECT
Brand, DESCRIPTION AS Model,
SECONDDESCRIPTION AS Description,
PRODUCT AS [Product Code], TYPE AS Batch, INACTIVE,
CORE AS [Core Range],
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
You may notice that the select statement will minus any items that are on a customer order from the SOH values. for clarity below is the line that does just that.
IIF([CUSTORD] IS NULL, ROUND(ON_HAND), (IIF(TYPE = 'DISP',ROUND(ON_HAND),ROUND(ON_HAND)-CUSTORD))) AS SOH
The problem i have is, that 1 product code, can have multiple batches, and if an item only has a qty of 1 in each batch, and then the customer order column also contains a 1, this results in 1 - 1 = 0.
However the customer orders column is really indicating that only 1 of the product codes in on a customer order, not that specific batch.
Is there a way to check if that product code has already been "Selected" and has a Customer Order Qty against it and if it does then ignore the customer order qty against this next batch in the table?
To help explain it a little here is a rough idea of the table that would be imported.
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
1
Apples
587554
1
1
Bananas
1548777
1
0
so in the table above with my existing select statement, my results would be
Apples 4 in batch 123456
Bananas 1 in batch 1548777
As the next two lines of apples would actually end up with a value of 0 in batches 234567 and 587554
my program is set to then only return to the user values of items they can sell with a SOH qty > 0
so i need the final datatable in my program to look like this:
Product
Batch_Number
ON_HAND
CUSTORD
Apples
123456
5
1
Apples
234567
1
0
Apples
587554
1
0
Bananas
1548777
1
0
In my table Batch Number is the unique identifier and does not occur twice in the table.
Im working in VB.NET so if it could not be done in the SQL select statement i could be open to the idea of adjusting the values in the dataset datatable, however that would probably be made harder by the fact that the SQL Select statement i'm using never actually imports the CUSTORD column of data into my datatable. As i was trying to handle the SOH values directly at the select statement level.
Hope i have not confused anyone, and explained it as simple as possible.
I have no idea what your initial code has to do with the question. But let me assume that you have a table in the format shown in the question and you want to set on_hand to 0 for all but the first row for each product. You can use:
select product, batch_number, custord,
iif( t.batch_number = (select top 1 t2.batch_number
from t as t2
where t2.product = t.product
order by t2.on_hand desc, t2.batch_number
),
t.on_hand, 0
) as adjusted_on_hand
from t
order by product, on_hand desc, batch_number

PostgreSql - How to create conditional column with the filter on another column?

I want to add 1 more columns where segment out whether the customer had sold at least one product or not.
Data example:
ProductID Customer Status
1 John Not sold
2 John Not Sold
3 John Sold
My expect result
ProductID Customer Status Sold_at_least_1
1 John Not sold Yes
2 John Not Sold Yes
3 John Sold Yes
4 Andrew Not Sold No
5 Andrew Not Sold No
6 Brandon Sold Yes
This is an example data. Sorry for any inconvenience as I unable to extract data out. Btw, appreciating for any helps.
You can do a window count of records of the same customer that have status = 'Sold' in a case expression:
select
t.*,
case when sum( (status = 'Sold')::int ) over(partition by customer) >= 1
then 'Yes'
else 'No'
end
from mytable
NB: note that this does not magically create new records (as shown in your sample data). This query gives you as many records in the resultset as there are in the table, with an additionnal column that indicates whether each cutsomer has at least one sold item in the table.
Here is a demo provided by VBokšić (thanks).
Another option is to use bool_or() as a window function. If you can live with a boolean column rather than a varchar with Yes/No, this makes the expression even simpler:
select productid, customer, status,
bool_or(status = 'Sold') over (partition by customer) as sold_at_least_one
from mytable;
Online example: https://rextester.com/NDN54253

SQL : how to distinguish between different rows with same value in some field and have a separate function applied to another field

I have a query output showing a list of orders. Some orders might occupy more then one record in the query output if those orders consist of sub-orders.Each sub-order occupies a separate line in the output. There is the OrderID column which has the same value for all sub-orders in the output:
OrderID Sub-Order Price
1 1 100
1 2 50
2 1 30
3 1 50
I need to add a column "Discount" to the output and fill it by following rules:
If certain order has one sub-order - the discount is 10% of the Price
If certain order has more than one sub-order, the discount is 20% on all sub-orders'
My query is a UNION of two SELECTs.
I use mssql with ms sql studio
Use CASE and COUNT window function
SELECT OrderID, Sub-Order, Price,
CASE WHEN (count(*) OVER (PARTITION BY OrderID)) > 1
THEN Price * 0.8
ELSE Price * 0.9
END
FROM ( table or <query> )

Omit item from Sum SQL

I'm very new to programming and SQL, I can't figure this one out, perhaps I haven't learned the concept yet, but I'm hoping you can help me. Sorry if it's too easy and boring.
/*2.37 Write an SQL statement to display the WarehouseID and the sum of
QuantityOnHand,grouped by WarehouseID. Omit all SKU items that have 3 or more items
on hand from the sum, and name the sum TotalItemsOnHandLT3 and display the results
in descending order of TotalItemsOnHandLT3.*/
SELECT WarehouseID, SUM(QuantityOnHand) AS TotalItemsOnHandLT3
FROM INVENTORY
GROUP BY WarehouseID
HAVING COUNT(WarehouseID) >= 3
ORDER BY TotalItemsOnHandLT3 DESC
"Omit all SKU items that have 3 or more items on hand from the sum", sounds more like :
FROM INVENTORY WHERE QuantitiyOnHand < 3
rather than :
HAVING COUNT(WarehouseID) >= 3
INVENTORY is the list of products (SKU = Stock Keeping Unit = Individual Product Stored in the warehouse) where every product has a WarehouseID. This warehouseID presumably determines where the product is stored.
By Omit all SKU items, it asks you to only display those products that are stored in minimum 3 places in the warehouse. This can be done with the having clause,
HAVING COUNT(WarehouseID) >= 3
I do not know the structure and data of your INVENTORY table, but simply put, Consider your data is like this:
SKUID WareHouseID QuantityOnHand
1 1 10
1 2 10
2 1 10
1 3 5
2 2 20
In the above case, Product = 1 (SKUID), is stored in 3 different warehouses whereas product 2 is stored in 2 warehouses. Hence,
SKUID COUNT(WareHouseID) SUM(QuantityOnHand)
1 3 25
2 2 30
In this case, your query will only "Omit" product 1, and not the product 2.
Its says Omit, they why
HAVING COUNT(WarehouseID) >= 3
and not
HAVING COUNT(WarehouseID) < 3