Numbering sequential numbers in a column in SQL - sql

I want to give a number to the value based on value in above row such that when the sequence breaks, it should again start from 1 otherwise should keep on increment the number.
The query is :
select'30300001' as lst union all
select'30300002' union all
select'30300003' union all
select'30300004' union all
select'30300001' union all
select'30300006' union all
select'30300007' union all
select'30300008' union all
select'30300009'
And the output I want to be as:
select'30300001' as lst,1 as rnk union all
select'30300002',2 union all
select'30300003',3 union all
select'30300004',4 union all
select'30300001',1 union all
select'30300006',1 union all
select'30300007',2 union all
select'30300008',3 union all
select'30300009',4
I tried it with row_number and rank functions but could not get the required output. How can I get the desired result?

If you have an orderingid (of some sort), then you can use the difference between your column and a column with a sequence. This identifies a group, which can then be used with other window functions:
select q.*,
row_number() over (partition by grp order by orderingid)
from (select q.*,
(lst - row_number() over (order by orderingid)) as grp
from query q
) q;
Note: this assumes that lst is actually a number or a value readily converted to a number.

Related

Removing doubling lines

I have written a union query but I need to eliminate the lines that are duplicated (line 2 and 3 in the column 'kods') and leave only distinct values of column 'kods'. How can that be done?
You need to decide which of the id values to discard using either min or max and group by the remaining columns. you don't need distinct and can union all since group by will perform the dedupe.
select kods, min(id) id, vards, uzvards from (
select kods, id, vards, uzvards
from dataset
union all
select kods, id, vards, uzvards
from dataset_2
)x
group by kods, vards, uzvards

Recursive ORDER BY

I have a USERS table which is a membership matrix like below. Table is unique on ID, and each ID belongs to at least one group, but could belong to all 3.
SELECT 1 AS ID, 0 AS IS_A, 0 AS IS_B, 1 AS IS_C FROM DUAL UNION ALL
SELECT 2,0,1,0 FROM DUAL UNION ALL
SELECT 3,0,1,1 FROM DUAL UNION ALL
SELECT 4,1,1,0 FROM DUAL UNION ALL
SELECT 5,1,1,0 FROM DUAL UNION ALL
SELECT 6,1,1,1 FROM DUAL UNION ALL
SELECT 7,0,1,1 FROM DUAL UNION ALL
SELECT 8,0,0,1 FROM DUAL UNION ALL
SELECT 9,1,0,0 FROM DUAL UNION ALL
SELECT 10,1,0,1 FROM DUAL UNION ALL
SELECT 11,0,0,1 FROM DUAL UNION ALL
SELECT 12,0,1,1 FROM DUAL
The final goal is to SELECT randomly a sample of at least 4 users from A, 3 from B and 5 from C (just an example) but with exactly 10 distinct IDs (otherwise the solution is trivial; just SELECT *).
The focus is less to determine if it's possible at all, but more to attempt a best effort to maximize memberships.
The output is expected to be unique on ID.
I can only think of a procedural way to achieve this:
Take the first ID with MAX(IS_A+IS_B+IS_C)
Check if the quotas are reached
If, for example, we already have 4 users from A, then we'll continue with the next ID with MAX(IS_B+IS_C), completely ignoring any further contributions from IS_A column
If we have already achieved all quotas, revert back to taking MAX(IS_A+IS_B+IS_C) to get "bonus" points
Stop upon reaching the overall maximum of 10
In essence, we prioritize and incrementally take the ID that has the most memberships in groups that have not reached the quota
However, I can't figure out how to do this in Oracle SQL since the ORDER BY would depend on not just the current row's values, but also recursively on whether the earlier rows have filled up the respective quotas.
I've tried ROWNUM, ROW_NUMBER(), SUM(IS_A) OVER (ORDER BY ...), RECURSIVE CTE but to no avail. Best I have is
WITH CTE AS (
SELECT ID, IS_A, IS_B, IS_C
, ROW_NUMBER() OVER (ORDER BY IS_A+IS_B+IS_C DESC) AS RN
FROM USERS
)
, CTE2 AS (
SELECT CTE.*
, GREATEST(4 - SUM(IS_A) OVER (ORDER BY RN), 0.001) AS QUOTA_A --clip negatives to 0.001
, GREATEST(3 - SUM(IS_B) OVER (ORDER BY RN), 0.001) AS QUOTA_B --so that when all quotas are exhausted,
, GREATEST(5 - SUM(IS_C) OVER (ORDER BY RN), 0.001) AS QUOTA_C --we still prioritize those that contribute most number of concurrent memberships
FROM CTE
)
SELECT ID FROM CTE2
ORDER BY QUOTA_A*IS_A + QUOTA_B*IS_B + QUOTA_C*IS_C DESC
FETCH NEXT 10 ROWS ONLY
but it does not work because QUOTA_A is computed based on ORDER BY RN instead of recursively.
Thanks in advance!

Cumulative Sum from value of two columns starting from second row MS SQL

I need to get the cumulative sum of column sales and growth starting from second row.
Sample data:
select 1 AS SN,'16000' AS Sales,'0' AS Growth,'16000' AS RequiredTotal
INTO #tempa
union select 2,'','500','16500'
union select 3,'','500','17000'
union select 4,'','500','17500'
union select 5,'','500','18000'
union select 6,'','500','18500'
union select 7,'','500','19000'
SELECT *
FROM #tempa
Here I need to get the requiredtotal column.
First value is the sales itself, And starting from second row, need to get the sum of 1st value of requiredtotal column and the growth column second row.
Use window functions:
select a.*,
(max(sales) over () +
sum(growth) over (order by sn)
) as required
from #tempa a;
Here is a db<>fiddle.
Note that I changed the data types in the fiddle so the numbers are actually numbers. Don't store numbers as strings.

In oracle How can I Find out one/two Columns data which corresponding other columns have maximum value

I'm Using Oracle where,
I have a Table(FE_IMPORT_LC Table) with data from where i give in following few column with data
TRANSMIT_LC_NO LIAB_AMT_LCY REM_LC_AMT_LCY IMP_AMEND_NO
108615020048 10022000 10022112 00
108615020048 10022000 10022112 01
108615020048 10022000 10022112 02
108615020048 11692000 8351760 03
I want to find out Data of the Red Marked Rows, which IMP_AMEND_NO column value is maximum. That means I want to find out one/two Columns data which corresponding other columns have maximum value.
So, I already create following query:
SELECT l1.liab_amt_lcy
FROM fe_import_lc l1
WHERE l1.transmit_lc_no = '108615020048'
AND l1.imp_amend_no = (SELECT MAX(l2.imp_amend_no)
FROM fe_import_lc l2
WHERE l2.transmit_lc_no = l1.transmit_lc_no)
But I want more effective query for this, If any one know about it please...Please give answer/reply as early as possible.
Try;
select liab_amt_lcy
from (
SELECT l1.liab_amt_lcy, imp_amend_no
FROM fe_import_lc l1
WHERE l1.transmit_lc_no = '108615020048'
order by imp_amend_no desc
)
where rownum < 2
Try something like below, where l1 would be your FE_IMPORT_LC table. Better to create a view with the logic of l2 table given below and then select.
with l1(TRANSMIT_LC_NO, LIAB_AMT_LCY, REM_LC_AMT_LCY, IMP_AMEND_NO) as(
select 108615020048,10022000,10022112,00 from dual union
select 108615020048,10022000,10022112,01 from dual union
select 108615020048,10022000,10022112,02 from dual union
select 108615020048,10022000,10022112,03 from dual
), l2 as(
select l1.*,row_number() over (partition by TRANSMIT_LC_NO order by IMP_AMEND_NO desc) as rno from l1)
select TRANSMIT_LC_NO, LIAB_AMT_LCY,REM_LC_AMT_LCY,IMP_AMEND_NO from l2
where rno=1;
If 2 rows have same max(IMP_AMEND_NO ) and if you want both, use below query(instead of row_number, I am using rank here. Rest same.
with l1(TRANSMIT_LC_NO, LIAB_AMT_LCY, REM_LC_AMT_LCY, IMP_AMEND_NO) as(
select 108615020048,10022000,10022112,00 from dual union all
select 108615020048,10022000,10022112,01 from dual union all
select 108615020048,10022000,10022112,03 from dual union all
select 108615020048,10022000,10022112,03 from dual
), l2 as(
select l1.*,rank() over (partition by TRANSMIT_LC_NO order by IMP_AMEND_NO desc) as rno from l1)
select TRANSMIT_LC_NO, LIAB_AMT_LCY,REM_LC_AMT_LCY,IMP_AMEND_NO from l2
where rno=1;
Here you dont have to specify TRANSMIT_LC_NO explicitely. If you have many records, then also you can get only row corresponding to max(IMP_AMEND_NO). But if you want to use this is a PL/SQL block, then put the TRANSMIT_LC_NO in the where clause in the select query from FE_IMPORT_LC and proceed like below.
You can try this, I don't have environment currently to test syntax error. However, I think with little modification it should work fine
select * from
(
select TRANSMIT_LC_NO, LIAB_AMT_LCY, REM_LC_AMT_LCY, IMP_AMEND_NO,
row_number() over(partition by transmit_lc_no order by imp_amend_no desc) as MAX_ID
from fe_import_lc
)
t where t.MAX_ID=1
and T.TRANSMIT_LC_NO = '108615020048';

SQL Server : UNION ALL but remove duplicate IDs by choosing first date of occurrence

I am unioning two queries but I'm getting an ID that occurs in each query. I do not know how to keep only the first time the id occurs. Everything else about the row is different. In general, it will be hard to know which of the two queries I will have to keep a duplicate on, therefore, I need a general solution.
I was thinking about creating a temp table and choosing the min date (once the date has been converted to an int).
Any ideas on the proper syntax?
You can do this using the row_number() function. This will assign a sequential number, starting with 1, to each row with the same id (based on the partition by clause). The ordering of the sequence is determined by the order by clause. So, the following assigns 1 to the earliest date for each id:
select t.*
from (select t.*,
row_number() over (partition by id order by date asc) as seqnum
from ((select *
from <subquery1>
) union all
(select *
from <subquery2>
)
) t
) t
where seqnum = 1;
The final where clause simply filters for the first occurrence.
If you use the keyword UNION, then it will remove duplicates from the two data sets you are working with. UNION ALL preserves duplicates.
You can view the specifics here:
http://www.w3schools.com/sql/sql_union.asp
If you want to only have one of the 2 records and they are not identical you will have to filter them yourself. You may need to do something like the following. THis may be possible to do with the one (select union select) block but this should get you started.
select *
from (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x1
, (
select id
, date
, otherstuf
from table_1
union all
select id
, date
, otherstuf
from table_2
) x2
where x1.id = x2.id
and x1.date < x2.date
Although rethinking this if you go down a path like this why bother to UNION it?