Generate a serial number based on quantity column in sql - sql

Hi Experts I have a table like this
T1
Order_no
Qty
1
3
2
5
3
1
4
3
I need to generate a column 'serial no' having values based on 'qty'
Output needed
OrderNo
Qty
SerailNo
1
3
1
1
3
2
1
3
3
2
5
1
2
5
2
2
5
3
2
5
4
2
5
5
3
1
1
4
3
1
4
3
2
4
3
3
Any suggestions?
Thanks in advance!!

You don't mention the specific database so I'll assume you are using PostgreSQL, aren't you?
You can use a Recursive CTE to expand the rows. For example:
with recursive
n as (
select order_no, qty, 1 as serial_no from t1
union all
select order_no, qty, serial_no + 1
from n
where serial_no < qty
)
select * from n order by order_no, serial_no
Result:
order_no qty serial_no
--------- ---- ---------
1 3 1
1 3 2
1 3 3
2 5 1
2 5 2
2 5 3
2 5 4
2 5 5
3 1 1
4 3 1
4 3 2
4 3 3
See running example at DB Fiddle.
EDIT FOR ORACLE
If you are using Oracle the query changes a bit to:
with
n (order_no, qty, serial_no) as (
select order_no, qty, 1 from t1
union all
select order_no, qty, serial_no + 1
from n
where serial_no < qty
)
select * from n order by order_no, serial_no
Result:
ORDER_NO QTY SERIAL_NO
--------- ---- ---------
1 3 1
1 3 2
1 3 3
2 5 1
2 5 2
2 5 3
2 5 4
2 5 5
3 1 1
4 3 1
4 3 2
4 3 3
See running example at db<>fiddle.

You should first provide the database you're using. Whether it's oracle, Sql Server, PostGreSQL will determine which procedural language to use. It's very likely that you'll need to do this in two steps:
1st: Duplicate the number of rows based on the column Qty using a decreasing loop
2nd: You'll need to create a sequential partionned column based on the Qty column

Related

SQL Query to get multiple resultant on single column

I have a table that looks something like this:
id name status
2 a 1
2 a 2
2 a 3
2 a 2
2 a 1
3 b 2
3 b 1
3 b 2
3 b 1
and the resultant i want is:
id name total count count(status3) count(status2) count(status1)
2 a 5 1 2 2
3 b 4 0 2 2
please help me get this result somehow, i can just get id, name or one of them at a time, don't know how to put a clause to get this table at once.
Here's a simple solution using group by and case when.
select id
,count(*) as 'total count'
,count(case status when 3 then 1 end) as 'count(status1)'
,count(case status when 2 then 1 end) as 'count(status3)'
,count(case status when 1 then 1 end) as 'count(status2)'
from t
group by id
id
total count
count(status3)
count(status2)
count(status1)
2
5
1
2
2
3
4
0
2
2
Fiddle
Here's a way to solve it using pivot.
select *
from (select status,id, count(*) over (partition by id) as "total count" from t) tmp
pivot (count(status) for status in ([1],[2],[3])) pvt
d
total count
1
2
3
3
4
2
2
0
2
5
2
2
1
Fiddle

Row_Number based on two columns

I am looking to try to create the row number below, I have tried so many options but none seem to work. I would appreciate help.
I want the row order to look at sub_id and for each one do a sequential number, 1, 2, 3... I then want it to look at disc, and if that changes, go back to 1 again. I have tried concatenating them and using a key, but I can't seem to get it to work.
ID sub_id disc ROW_NUMBER
1 1 OT 1
1 1 OT 2
1 1 OT 3
1 2 DT 1
1 2 DT 2
1 3 SL 1
1 3 SL 2
1 4 PH 1
1 4 PH 2
1 4 OT 1
1 5 OT 1
1 5 PH 2
1 5 DT 1
1 6 DT 1
1 6 DT 2
1 6 DT 3
1 7 SL 1
1 7 SL 2
1 7 DT 1
1 8 SL 1
1 8 SL 2
1 8 SL 3
1 9 DT 1
1 9 DT 2
1 9 DT 3
1 10 PH 1
1 10 DT 1
1 10 DT 2
1 11 OT 1
1 11 OT 2
1 11 OT 3
1 12 OT 1
1 12 OT 2
1 12 OT 3
Update
row_number() OVER (PARTITION BY sub_id ORDER BY disc) does not work. The ordering goes wrong when sub_id changes to 2. at this point it needs to revert back to 1, but it is 2.
You seem to want:
row_number() over (partition by id, sub_id, disc order by id)
Note: You do not have a column that specifies the ordering of the columns -- or even uniquely identifies each row. Hence, this just uses order by id. You might want to include some other column there.
SELECT ID , sub_ID , disc , ROW_NUMBER() OVER (PARTITION BY sub_ID ORDER BY disc) from your table

How to Subtotal Value with MAX

1.I have data as follows (just a subset - there are 20K records)
sku,id
1 1
1 2
1 2
1 2
1 3
1 4
1 1
1 2
1 3
1 4
1 4
1 4
1 5
1 6
1 6
2 1
2 1
2 2
2 3
2 3
2 3
2 4
2 4
2 5
2 5
2 6
2 7
2 1
2 2
2 3
The above values translate to
1 = 4 records
1 = 6 records
2 = 7 records
2 = 3 records
The MAX would just give me 6 for one and 7 for 2
The actual total is 1 = 10 and 2 = 10
How do I sum up to get the correct values?
You can use order by and some way of limiting rows. In standard SQL this would be:
select t.*
from t
order by id desc
fetch first 2 rows only;
However, some databases might use limit or select top or some other method.
No handling of ties here. Thousands of other questions handle this topic.
select sku, id
from (
select *, row_number() over (order by id desc) rn
from T
) t
where rn <= 2
order by rn desc;

Finding Distinct values across multiple columns and rows in SQL

I have data like this
Id code1 code2 code3 code4 code5 code6
1 2 3 4 5 6 7
1 4 5 2 3 7 6
1 7 6 5 2 3 4
1 5 7 6 4 3 2
1 7 5 6 3 2 4
I need to identify the distinct codes from this set of 6 codes across 5 rows and 6 columns and display them in any order of 6 rows with ID and code
OUTPUT
ID Code
1 7
1 6
1 2
1 3
1 5
1 4
enter image description here
One method is to use union :
select id, code
from (select id, code1 as code
from table t
union
select id, code2
from table t
. . .
select id, code6
from table t
) t;

Add position column based on order by - Oracle

I have this table with the following records:
table1
id ele_id_1 ele_val ele_id_2
1 2 123 1
1 1 abc 1
1 4 xyz 2
1 4 456 1
2 5 22 1
2 4 344 1
2 3 6 1
2 2 Test Name 1
2 1 Hello 1
I am trying to add position for each id when ele_id_1 and ele_id_2 is order by ASC.
Here is the output:
id ele_id_1 ele_val ele_id_2 position
1 2 123 1 2
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 3
2 5 22 1 5
2 4 344 1 4
2 3 6 1 3
2 2 Test Name 1 2
2 1 Hello 1 1
I have 34 million rows in table1, so would like to use an efficient way of doing this.
Any idea on how I can add position with values?
I think you want row_number() used like this:
select row_number() over (partition by id
order by ele_id_1, ele_id_2
) as position
Oracle can use an index for this, on (id, ele_id_1, ele_id_2).
I should note that for your example data order by ele_id_1, ele_id_2 and order by ele_id_2, ele_id_1 produce the same result. Your question suggests that you want the first.
So, you would get
id ele_id_1 ele_val ele_id_2 position
1 1 123 2 2
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 3
Rather than:
id ele_id_1 ele_val ele_id_2 position
1 1 123 2 3
1 1 abc 1 1
1 4 xyz 2 4
1 4 456 1 2
EDIT:
If you want to update the data, then merge is probably the best approach.
MERGE INTO <yourtable> dest
USING (select t.*,
row_number() over (partition by id
order by ele_id_1, ele_id_2
) as new_position
from <yourtable> t
) src
ON dest.id = src.id AND
dest.ele_id_1 = src.ele_id_1 AND
dest.ele_id_2 = src.ele_id_2
WHEN MATCHED THEN UPDATE
SET desc.postition = src.new_position;
Note that updating all the rows in a table is an expensive operation. Truncating the table and recreating it might be easier:
create table temp_t as
select t.*,
row_number() over (partition by id
order by ele_id_1, ele_id_2
) as new_position
from t;
truncate table t;
insert into t ( . . . )
select . . . -- all columns but position
from temp_t;
However, be very careful if you truncate the table. Be sure to back it up first!