Need to fetch result row on basis of order of value - sql-server

Item No Date Item Type Item No Date Item Type
12345 12/17/2021 High 12345 12/17/2021 HIGH
23456 12/17/2021 Low 23456 12/17/2021 Low
78901 12/17/2021 Out 78901 12/17/2021 Out
12345 11/17/2021 Low 12345 11/17/2021 Low
23456 11/17/2021 High 23456 11/17/2021 High
78901 11/17/2021 Low 78901 11/17/2021 Low
12345 12/17/2021 HIGH
23456 12/17/2021 High Result Table
78901 12/17/2021 Low
78901 12/17/2021 High
Source table
I have source table at right side and require result table at left side. Result are on basis of column 'ITEM TYPE' :- Out, High , Low . IF I have 2 row having different 'ITEM TYPE'
then it should select only one value on basis of Out>Low>High.
Eg:- If 'ITEM NO' Have value 12345 and it has High , Low and High, then it it should take value as High.
If it has Low and High only then it should take it as Low and if it has only High , it will take it as High.
Please help me with query , how I can achieve it.

I'd rank the rows per item number and date combination, and then query the "first" one only:
SELECT item_no, date, item_type
FROM (SELECT item_no, date, item_type
RANK() OVER (PARTITION BY item_no, date
ORDER BY CASE item_type WHEN 'Out' THEN 1
WHEN 'Low' THEN 2
WHEN 'High' THEN 3
END) AS rk
FROM my_table) t
WHERE rk = 1

Related

How to order by one column, but rank based on a different column that is not numeric?

I have four columns that I am trying to rank. They need to be grouped by employee ID and then listed low to high by order number. Then when everything is in order, I'm really trying to get the ranking of where the city falls in that order. If the same city is listed after another for the same employee then I want that those ranked the same.
An example of the table is below. The order is correct, but the ranking is not for what I'm trying to do.
Name Employee_ID Order_Number City Rank
John 1 1 Boston 1
John 1 2 Boston 2
Will 2 1 Peabody 1
Will 2 2 Weston 2
Will 2 3 Newton 3
select Name, Employee_ID, Order_Number, City,
dense_rank() over(partition by Employee_ID order by Order_Number) as rank
from #Employee
How I would actually want the results are:
Name Employee_ID Order_Number City Rank
John 1 1 Boston 1
John 1 2 Boston 1
Will 2 1 Boston 1
Will 2 2 Weston 2
Will 2 3 Newton 3
Then I would eventually remove the duplicate Cities to end up with:
Name Employee_ID Order_Number City Rank
John 1 1 Boston 1
Will 2 1 Boston 1
Will 2 2 Weston 2
Will 2 3 Newton 3
You can try this following script to get your desired output.
SELECT Name, Employee_ID, Order_Number, City ,
ROW_NUMBER() OVER (PARTITION BY Employee_ID ORDER BY Order_Number) rank
(
select Name, Employee_ID, Order_Number, City,
dense_rank() over(partition by Employee_ID,city order by Order_Number) as rank
from #Employee
)A
WHERE rank = 1
Output from your result set is-
Name Employee_ID Order_Number City rank
John 1 1 Boston 1
Will 2 1 Peabody 1
Will 2 2 Weston 2
Will 2 3 Newton 3
Check output of the script on Fiddle.
You can use LAG() to check if the previous city is the same. If the previous city is different or null then we take rank as it is, if cities are same then rank - 1 gives us the same number as row above. Demo
with cte as (select Name, Employee_ID, Order_Number, City,
dense_rank() over (partition by Employee_ID order by Order_Number) as rank,
lag(City) over (partition by Employee_ID order by Order_Number) as previousCity
from #Employee)
select
Name, Employee_ID, Order_Number, City,
case when previousCity = city then rank - 1
else rank end as rank
from cte

How can i implement this query in sql server?

I'm beginner in sql server,have two table ,table GetOnlineBills with this shape:
--Telno-- --Cycle-- --Bill--
nchar(20) nchar(20) float
And table 25Percantage:
--Telno-- --Cycle-- --Bill--
nchar(20) nchar(20) float
want to write query or tsql for analysis Telno in GetOnlineBill table with this flow:
1-fetch Telno ang get it bill value in Cycle 951 and Cycle 952
2-If Bill(952)>Bill(951) then write into 25 percantage this data (Bill(952)-Bill(951))
into GetOnlineBill's table write subscribe Bill information per cycle,For example have two subscribe(in really world have 1 million subscribe) with this plan:
into the GetOnlineBills one mounth data is this:
--Telno-- --Cycle-- --Bill--
12345 951 300
54321 951 500
and other month data is :
--Telno-- --Cycle-- --Bill--
12345 952 400
54321 952 600
and final GetOnlineBill for two mounth is:
--Telno-- --Cycle-- --Bill--
12345 951 300
54321 951 500
12345 952 400
54321 952 600
Now,i want analysis GetOnlineBill,want write query or tsql to create final 25Percantage table show me this:
--Telno-- --Cycle-- --Bill--
12345 951-952 100 ------>Bill(952)-Bill(951) Minus
54321 951-952 300
----------------------------------------
Explain:
Bill:Field Name on GetOnlineBill table
952:Cycle
951:Cycle
How can i write query or tsql for that purpose?please write and post me.thanks all.
Inner join should help you:
SELECT y.Telno,
t.Cycle+'-'+y.Cycle Cycle,
y.Bill - t.Bill Price
FROM YourTable y
INNER JOIN YourTable t
ON y.Telno = t.TelNo AND CAST(y.Cycle as int)-1 = CAST(t.Cycle as int)
Output:
Telno Cycle Price
12345 951-952 100
54321 951-952 100
If Cycle column can not be converted to integer then you need some other field to order table right way and do join with that field (or OUTER APPLY)
Try as the below:
DECLARE #Tbl TABLE (TelNo NCHAR(20), Cycle NCHAR(20), Bill FLOAT)
INSERT INTO #Tbl
VALUES
('12345', '951', 300),
('12345', '952', 400),
('54321', '951', 500),
('54321', '952', 600)
;WITH CTE
AS
(
SELECT *, DENSE_RANK() OVER (ORDER BY Cycle) MonthId
FROM #Tbl
)
SELECT
CurrentMonth.TelNo,
CurrentMonth.Cycle + '-' + NextMonth.Cycle Cycle,
CASE
WHEN NextMonth.Bill > CurrentMonth.Bill THEN NextMonth.Bill - CurrentMonth.Bill
ELSE CurrentMonth.Bill END Bill -- Change as you want
FROM
CTE CurrentMonth LEFT JOIN
CTE NextMonth ON CurrentMonth.TelNo = NextMonth.TelNo AND (NextMonth.MonthId - 1) = CurrentMonth.MonthId
WHERE
NextMonth.MonthId IS NOT NULL
Result:
TelNo Cycle Bill
-------------------- ------------------------ ---------
54321 951-952 100
12345 951-952 100

How can i write query to calc percent of the difference two field?

I'm new in sql server,have this table on sql server:
Telno nchar(20)
CurBill float
Cycle nchar(8)
and into that table has this data:
Telno CurBill Cycle
123 2000 951
123 2500 952
write this query for calculate difference two number:
SELECT y.Telno,
t.Cycle+'-'+y.Cycle Cycle,
y.CurBill - t.CurBill Price
FROM [ClubEatc].[dbo].[GetOnlineBills] y
INNER JOIN [ClubEatc].[dbo].[GetOnlineBills] t
ON y.Telno = t.TelNo AND CAST(y.Cycle as int)-1 = CAST(t.Cycle as int)
that query minus two CurBill per Cycle and show me this:
123 951-952 1000 ----->calc this formull(CurBill(952)-CurBill(951))
now want to show percent of decrease or increase of CurBill minus,for example show me this:
123 951-952 150%--->calc formulla(CurBill(951)-CurBill(952))/CurBill(951) *100
and other example imagine GetOnlineBills data is this:
Telno CurBill Cycle
123 2500 951
123 2000 952
and show me this:
123 951-952 -150%--->calc formulla(CurBill(951)-CurBill(952))/CurBill(951) *100
How can i implant that?thanks.

How to write sql select in order to obtain percentage

I define a view which contains 2 columns
France Wine
France Fromage
France Meat
France Chips
Belgium Bier
Belgium Chips
Belgium Chocolate
i love Bier and Chips
which select in order to obtain the best country
like
Belgium 66%
France 25%
You want the count for Bier and Chips for each country, divided by the total item count for each country.
The count for Bier and Chips goes something like this:
COUNT(CASE WHEN Item IN ('Bier', 'Chips') THEN 1 END)
If Item is Bier or Chips, the CASE returns 1, which is counted. If it's not Bier or Chips, the CASE returns a NULL, which is not counted.
Putting it all together:
SELECT
Country,
COUNT(CASE WHEN Item IN ('Bier', 'Chips') THEN 1 END) /
CAST(COUNT(*) AS NUMERIC)
AS BierChipsPercent
FROM myTable
GROUP BY Country
Why the CAST(COUNT(*) AS NUMERIC)? Because without it, SQL Server appears to be treating both COUNTs as integer so it's truncating the result when they're divided. Casting to NUMERIC makes it behave, so 1/4 will yield 0.25 instead of zero.
The above query will give you:
Belgium 0.6666666666
France 0.25
To get the percentage, just multiply by 100. To get whole numbers, apply the ROUND() function:
SELECT
Country,
ROUND(
COUNT(CASE WHEN Item IN ('Bier', 'Chips') THEN 1 END) /
CAST(COUNT(*) AS NUMERIC) * 100, 0)
AS BierChipsPercent
FROM myTable
GROUP BY Country
This will give you:
Belgium 67
France 25
Note that Belgium's percentage rounds up to 67. If you want it to be 66, use FLOOR instead of ROUND.
There's a SQL Fiddle for this here.
This is my select but I understood that I can also write with over() ???
SELECT c1 ,
convert(
decimal(5,2),
100.00 *
(select COUNT(*) from myTable WHERE c1=t.c1 and (c2='Chips' or c2='Bier'))
/
(SELECT count(*) FROM myTable WHERE c1=t.c1)
) AS percentage
FROM myTable t
group by c1
c1 percentage
Belgium 66.67
France 25.00

Find and replace rows with similar value in one column in Oracle SQL

I want to find the rows which are similar to each other, and replace them with a new row. My table looks like this:
OrderID | Price | Minimum Number | Maximum Number | Volume
1 45 2 10 250
2 46 2 10 250
3 60 2 10 250
"Similar" in this context means that the rows that have same Maximum Number, Minimum Number, and Volume. Prices can be different, but the difference can be at most 2.
In this example, orders with OrderID of 1 and 2 are similar, but 3 is not (since even if it has same Minimum Number, Maximum Number, and Volume, its price is not within 2 units from orders 1 and 2).
Then, I want orders 1 and 2 be replaced by a new order, let's say OrderID 4, which has same Minimum Number and Maximum Number. Its Volume hass to be sum of volumes of the orders it is replacing. Its price can be the Price of any of the previous orders that will be deleted in the output table (45 or 46 in this example). So, the output for the example above would be:
OrderID | Price | Minimum Number | Maximum Number | Volume
4 45 2 10 500
3 60 2 10 250
Here is a way to do this in SQL Server 2012 or Oracle. The idea is to use lag() to find where groups should begin and end and then aggregate.
select min(id) as id, min(price) as price, MinimumNumber, MaximumNumber, sum(Volume)
from (select t.*,
sum(case when prev_price < price - 2 then 1 else 0 end) over
(partition by MinimumNumber, MaximumNumber, Volume order by price) as grp
from (select t.*,
lag(price) over (partition by MinimumNumber, MaximumNumber, Volume
order by price
) as prev_price
from table t
) t
) t
group by grp, price, MinimumNumber, MaximumNumber;
The only issue is the setting of the id. I'm not sure what the exact rule is for that.

Resources