SQL Standard Value and Variations - sql

Below is a sample of data
UnitID ITEM_Num Price
13446 71079 45.57
13447 71079 45.57
13448 71079 52.50
13449 71079 45.57
13450 71079 36.22
The actual dataset has roughly 100 unique UnitIDs and 700 unique Item_Num values. I am trying to determine the most common price for each Item_Num and then select any records that vary from that standard by more than a specified percent.
Ideally we would have a standard Price value for each item but we don't. What is the best way to find the most common value. Also is there a function that might be able to quickly rank the Items with the most variation is Price.
This is SQL Server 2012.

You can use GROUP BY statement:
SELECT Price, count(*) FROM my_table GROUP BY Price ORDER BY Price ASC
Hope this helps!

The following query should work in SQL Server. It should give back each ITEM_Num with a price 10% lower or higher than the most common price.
;WITH cte AS (
SELECT
RANK() OVER (PARTITION BY ITEM_Num ORDER BY COUNT(1) DESC) AS 'Rank'
, ITEM_Num
, Price
FROM Units
GROUP BY ITEM_Num, Price
)
SELECT u1.UnitID
, u1.ITEM_Num
, u1.Price
, u2.Price AS 'most common price'
FROM Units u1
INNER JOIN cte AS u2
ON u2.ITEM_Num = u1.ITEM_Num
AND u2.Rank = 1
WHERE ABS(u1.Price - u2.Price) >= (u2.Price * 0.1);
EDIT: I wrote the query not knowing your DBMS, could probably be more efficient using the ranking functions of SQL Server.
EDIT 2: http://sqlfiddle.com/#!6/74940/33

Create table #t(
UnitID int,
Item_Num int,
Price money
)
Insert into #t(Unitid, Item_Num, Price)
values(13446, 71079, 45.57 ),
(13447, 71079, 45.57),
(13448, 71079, 52.50),
(13449, 71079, 45.57),
(13450, 71079, 36.22)
;with cte as (
Select
Unitid, Item_Num, Price,
Row_Number() over ( partition by item_num order by price) rownum
from #t
)
Select
u.UnitID,
u.Item_Num,
u.Price,
U1.price as CommonPrice,
u.RowNum,
U.Price*0.1,
(u.price +(u.price*0.1)) as NewPrice
from cte as U
inner join #t u1 on u.item_num =u1.item_num
where u.rownum =1

Related

Finding max date for a concatenated field

I am trying to take a very large product table that has one row per product status and date, and get down to a table that demonstrates the latest status for each product they own.
I think if I concatenate the account and product columns and then use that to find the max date but I'm stumbling with my code. Would appreciate any insight!
Example table
Account
Product
EffectiveDate
Status
10000
Product A
5/1/2021
Live
10000
Product A
9/1/2020
Decomissioned
10000
Product B
12/1/2021
Implementing
My goal output would be:
Account
Product
EffectiveDate
Status
10000
Product A
5/1/2021
Live
10000
Product B
12/1/2021
Implementing
SELECT X.Account,X.Product,X.EffectiveDate,X.Status FROM
(
SELECT E.Account,E.Product,E.EffectiveDate,E.Status,
ROW_NUMBER()OVER(PARTITION BY E.Product ORDER BY E.EffectiveDate DESC)AS XCOL
FROM Example_table AS E
)X WHERE X.XCOL=1
May be something like this will be suitable
For some DBMS you can use a window function and qualify. On others (SQL Server) you can use top and a window function.
create table T1 (Account int, Product varchar(255), EffectiveDate date, status varchar(255));
insert into T1 (Account, Product , EffectiveDate , "STATUS" ) values
(10000, 'Product A', '2021-05-01', 'Live'),
(10000, 'Product A', '2020-09-01', 'Decomissioned'),
(10000, 'Product B', '2021-12-01', 'Implementing');
-- Snowflake, Teradata, Oracle, others...
select Account, Product, EffectiveDate, Status
from T1
qualify row_number() over (partition by Account, Product order by EffectiveDate desc) = 1
;
-- SQL Server
select top 1 with ties Account, Product, EffectiveDate, Status
from T1
order by row_number() over (partition by Account, Product order by EffectiveDate desc);

Getting the lastest entry grouped by ID

I have a table with stock for products. The problem is that every time there is a stock change, the new value is stored, together with the new Quantity. Example:
ProductID | Quantity | LastUpdate
1 123 2019.01.01
2 234 2019.01.01
1 444 2019.01.02
2 222 2019.01.02
I therefore need to get the latest stock update for every Product and return this:
ProductID | Quantity
1 444
2 222
The following SQL works, but is slow.
SELECT ProductID, Quantity
FROM (
SELECT ProductID, Quantity
FROM Stock
WHERE LastUpdate
IN (SELECT MAX(LastUpdate) FROM Stock GROUP BY ProductID)
)
Since the query is slow and supposed to be left joined into another query, I really would like some input on how to do this better.
Is there another way?
Use analytic functions. row_number can be used in this case.
SELECT ProductID, Quantity
FROM (SELECT ProductID, Quantity, row_number() over(partition by ProductID order by LstUpdte desc) as rnum
FROM Stock
) s
WHERE RNUM = 1
Or with first_value.
SELECT DISTINCT ProductID, FIRST_VALUE(Quantity) OVER(partition by ProductID order by LstUpdte desc) as quantuity
FROM Stock
Just another option is using WITH TIES in concert with Row_Number()
Full Disclosure: Vamsi's answer will be a nudge more performant.
Example
Select Top 1 with ties *
From YourTable
Order by Row_Number() over (Partition By ProductID Order by LastUpdate Desc)
Returns
ProductID Quantity LastUpdate
1 444 2019-01-02
2 222 2019-01-02
So you Could use a CTE(Common Table Expression)
Base Data:
SELECT 1 AS ProductID
,123 AS Quantity
,'2019-01-01' as LastUpdate
INTO #table
UNION
SELECT 2 AS ProductID
,234 AS Quantity
,'2019-01-01' as LastUpdate
UNION
SELECT 1 AS ProductID
,444 AS Quantity
,'2019-01-02' as LastUpdate
UNION
SELECT 2 AS ProductID
,222 AS Quantity
,'2019-01-02' as LastUpdate
Here is the code using a Common Table Expression.
WITH CTE (ProductID, Quantity, LastUpdate, Rnk)
AS
(
SELECT ProductID
,Quantity
,LastUpdate
,ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY LastUpdate DESC) AS Rnk
FROM #table
)
SELECT ProductID, Quantity, LastUpdate
FROM CTE
WHERE rnk = 1
Returns
You could then Join the CTE to whatever table you need.
row_number() function might be the most efficient, but the big slow down in your query is the use of the IN statement when used on a subquery, it's a little bit of a tricky one but a join is faster. This query should get what you want and be much faster.
SELECT
a.ProductID
,a.Quantity
FROM stock as a
INNER JOIN (
SELECT
ProductID
,MAX(LastUpdate) as LastUpdate
FROM stock
GROUP BY ProductID
) b
ON a.ProductID = b.ProductId AND
a.LastUpdate = b.LastUpdate

SQL filter to replace duplicate value records with one single custom value record

I am trying to create a report that shows a count of items (store_Product) purchased by store location(store_ID).
My issue is that when a distinct store location purchases both product_a and product_b, then I need the report to show one record of that store_ID with store_Product as "product_A" instead of having two records with same store_ID and both product_A and product_B.
However, if a distinct store location only purchases product_A OR product_B (but not both) then it would show one record of that store_ID along with what product it purchased as it normally does now.
On the left is what I am getting right now and on the right is what I want the result to look like:
How can I achieve this result?
Thanks!
In Microsoft SQL Server, you can achieve this by using CTE:
CREATE TABLE #temp (
store_id int,
store_product varchar(25)
)
INSERT INTO #temp
VALUES (100, 'product_A')
, (100, 'product_B')
, (200, 'product_B')
, (300, 'product_A')
, (400, 'product_B')
, (400, 'product_A')
;WITH cte
AS (SELECT
*,
ROW_NUMBER() OVER (PARTITION BY store_id ORDER BY store_id, store_product) AS rn
FROM #temp)
SELECT
store_id , store_product
FROM cte
WHERE rn = 1
DROP TABLE #temp
select store_id, min(store_product) as store_product
from table_name
group by store_id;
... its another dirty trick that will work with the sample data ;)
In a comment to an answer you are correcting your request. You want to suppress product_B when the same store also has product_A. All other rows shall remain in the result. At least this is how I understand this now.
One way to achieve this is with a NOT IN (or NOT EXISTS) clause:
select
store_id,
store_product
from mytable
where store_product <> 'product_B'
or store_id not in (select store_id from mytable where store_product = 'product_A');
or if you find that more readable:
select
store_id,
store_product
from mytable
where not
(
store_product = 'product_B' and
store_id in (select store_id from mytable where store_product = 'product_A')
);

How to run distinct and Sum in one query in sql server 2008 R2

I have a table #1 as shown in image attached. First i want to sum all quantity of all distinct id. Then want to show number of id that have same quantity.
Use SUM and COUNT:
SELECT
COUNT(*) AS totalId,
qty
FROM (
SELECT
id, SUM(qty) AS qty
FROM tbl
GROUP BY id
)t
GROUP BY qty
ONLINE DEMO
Try this one after creating a temporary table
create table #Temp
(
id int,
qty int
)
Insert Into #Temp
SELECT id, SUM(qty)
FROM yourTable
group by id
SELECT * FROM #Temp
SELECT Count(id) , qty
FROM #Temp
GROUP BY qty
ORDER BY qty DESC
to show the sum of all quantities of all distinct id:
SELECT id,SUM(qty) FROM table GROUP BY id;
to show number of id that have same quantity
SELECT count(id),quantity FROM (SELECT id,SUM(qty) AS quantity FROM table GROUP BY id) GROUP BY quantity

How to select the record with minimum value from table?

I have table BIDS, which contains a lot of columns and rows but I only want to select a row which contains lowest BIDPRICE.
Select min(Cast(Bids.BidPrice as INT)), BidBidderName from bids BidBidderName
but it throws error
Column 'bids.BidBidderName' is invalid in the select list because it
is not contained in either an aggregate function
When I put BidderName in Group by then it shows all records but I only want record which contains lowest bid price.
Here is an option that will get just the row with the lowest price.
Select top 1 BidPrice
, BidBidderName
from bids
order by Cast(BidPrice as INT)
You can use subquery:
Select BidPrice, BidBidderName from bids
where Bids.BidPrice in (Select min(Cast(b.BidPrice as INT)) from bids b)
Or INNER JOIN:
Select b1.BidPrice, b1.BidBidderName from bids b1
inner join (select Min(BidPrice) BidPrice from #bids) as b2 on b.BidPrice = b2.BidPrice
If you only want rows that have the lowest bid price one solution is to use a subquery to find the minimum price like this:
Select BidPrice, BidBidderName
from bids
where BidPrice = (select min(Cast(BidPrice as INT)) from bids)
If the BidPrice is either money or a numeric type (which it most likely should be) the cast to int is not necessary.
If you do
Select Min(BidPrice) BidPrice, BidBidderName
from bids
group by BidBibberName
you would instead get the lowest bid for every bidder.
try:
Row_Number()
;with cte1
as
(
select BidderName ,BidPrice,Row_Number() Over(order by price asc) as rn from bids
)
select * from cte1 where rn=1;
Or
Min(BidPrice) Over(PARTITION BY BidderName order by price asc)
select top 1 BidderName ,Min(BidPrice) Over(PARTITION BY BidderName order by price asc) as minBidPrice from bids