Oracle_ ROW_NUMBER for paging hierarchy query - sql

This time I face a problem that is paging query for a hierarchy table.
table_name(id varchar2(50), id_parent varchar2(50) );
So for sample data I have:
WITH table_name AS
(
SELECT '3' id, '' id_parent FROM DUAL UNION ALL
SELECT '5' id, '3' id_parent FROM DUAL UNION ALL
SELECT 's' id, '3' id_parent FROM DUAL UNION ALL
SELECT '4' id, 'as' id_parent FROM DUAL UNION ALL
SELECT 'aa' id, 'as' id_parent FROM DUAL UNION ALL
SELECT 'as' id, '3' id_parent FROM DUAL UNION ALL
SELECT 'ad' id, '3' id_parent FROM DUAL UNION ALL
SELECT '2' id, '' id_parent FROM DUAL
)
SELECT LPAD('-', 2 * (level - 1), '-') || id AS id1,
id_parent,
rownum --Seem not legit here
FROM table_name
START WITH id_parent IS NULL
CONNECT BY PRIOR id = id_parent
--ORDER SIBLINGS BY id
;
This is expected output:
id id_parent rownum
2 1
3 2
--5 3 3
--ad 3 4
--as 3 5
----4 as 6
----aa as 7
--s 3 8
For now I count on rownum for row_number to make paging. As Oracle hierarchy query's doc, this make sure I can display the tree as pre-order Traveral that's what we want, but as SQL in general, IMO it don't guarantee that the same-level-nodes will be sorted (or not?).
So I need something like ROW_NUMBER() OVER (ORDER SIBLINGS BY id). But I have got no luck searching for something like that.
Is there some way to work with this?

Order first and then generate the ROWNUM afterwards using a sub-query:
SELECT t.*,
ROWNUM
FROM (
SELECT LPAD('-', 2 * (level - 1), '-') || id AS id1,
id_parent
FROM table_name
START WITH id_parent IS NULL
CONNECT BY PRIOR id = id_parent
ORDER SIBLINGS BY id
) t;
You need the outer query as the order in which execution happens in a query is:
The rows are selected;
Then the WHERE clause filters are applied (and the ROWNUM pseudo-column is
generated for each row that matches all the WHERE clause filters - in this case there is no WHERE clause so all rows will be numbered);
Then the ORDER BY clause is applied.
Applying this in a single query will get the rows found in the database then give them a row number and finally order those rows (not what you want). Using an inner query you can force the ORDER BY clause to be applied first and then the generation of the row numbers will occur, subsequently, in the execution of the outer query.

Related

Oracle Select max where a certain key is matched

i'm working with oracle, plSql, i need to query a table and select the max id where a key is matched, now i have this query
select t.* from (
select distinct (TO_CHAR(I.DATE, 'YYMMDD') || I.AUTH_CODE || I.AMOUNT || I.CARD_NUMBER) as kies, I.SID as ids
from transactions I) t group by kies, ids order by ids desc;
It's displaying this data
If i remove the ID from the query, it displays the distinct keys (in the query i use the alias KIES because keys was in blue, so i thought it might be a reserved word)
How can i display the max id (last one inserted) for every different key without displaying all the data like in the first image??
greetings.
Do you just want aggregation?
select thekey, max(sid)
from (select t.*,
(TO_CHAR(t.DATE, 'YYMMDD') || t.AUTH_CODE || t.AMOUNT || t.CARD_NUMBER) as thekey,
t.SID
from transactions t
) t
group by thekey
order by max(ids) desc;
Since you haven't provided data in text format, its difficult to type such long numbers and recreated the data.
However I think you can simply use the MAX analytical function to achieve your results.
with data as (
select 1111 keys,1 id from dual
union
select 2222, 1 from dual
union
select 1111, 2 from dual
union
select 2222,3 from dual
union
select 9999, 1 from dual
union
select 1111, 5 from dual
)
select distinct keys, max(id) over( partition by (keys)) from data
This query returns -
KEYS MAX(ID)OVER(PARTITIONBY(KEYS))
1111 5
9999 1
2222 3

replacement of Offset Limit in SQL Server

We have DataTemp table which has the records in desc order.
select * from (
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
sno - Auto Id.
id - code of the Doors*.
N_th_Record - for denoting the n the record.
At a time, only three* records per Door are need to store on this table. For example Door 'a' has new entry(means 4th record) then first of 'a' Door need to delete.
4th record:
select * from (
select 10,'a',4 union --- new entry
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union -- need to delete
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
I do following query. But I need easiest way for deleting the row. Because, we are try to reduce the time consumption of over all project.
delete from door where sno = (
select sno from (
select 10,'a',4 union
select 9,'a',3 union
select 8,'a',2 union
select 7,'b',3 union
select 6,'a',1 union
select 5,'b',2 union
select 4,'c',3 union
select 3,'c',2 union
select 2,'b',1 union
select 1,'c',1
) door (sno,id, N_th_Reocord)
where id = 'a'
order by sno desc -- For 'DataTemp' *order by* is no needed.
offset 3 rows fetch next 1 rows only
)
Note:
Three rows and three Door are given for example. Actually we work with 144 rows per 12 Doors.
Before this delete, we check lot of Business rules.
Version: SQL Server 2012
You could use ROW_NUMBER:
WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY id ORDER BY sno DESC) rn FROM t)
DELETE FROM cte WHERE rn > 3;
db<>fiddle demo

SQL assigning incremental ID to subgroups

As the title says, I'm trying to add an extra column to a table which autoincrements everytime a different string in another column changes.
I would like to do this in a query.
Example:
MyCol GroupID
Cable 1
Cable 1
Foo 2
Foo 2
Foo 2
Fuzz 3
Fizz 4
Tv 5
Tv 5
The GroupID column is what I want to accomplish.
We can be sure that MyCol's strings will be the same in each subgroup (Foo will always be Foo, etc).
Thanks in advance
If I understand correctly, you can use dense_rank():
select t.*, dense_rank() over (order by col1) as groupid
from t;
You could make a temporal table with the distinct value of the MyCol and get the groupId throught the RowNumber of the temp table, and join the rownumbered result with your table.
This is a raw example in oracle:
WITH data AS
(SELECT 'Cable' MyCol FROM dual
UNION ALL
SELECT 'Cable' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Foo' FROM dual
UNION ALL
SELECT 'Fuzz' FROM dual
UNION ALL
SELECT 'Fizz' FROM dual
UNION ALL
SELECT 'Tv' FROM dual
UNION ALL
SELECT 'Tv' FROM dual
),
tablename AS
(SELECT * FROM data
),
temp AS
( SELECT DISTINCT mycol FROM tablename
),
temp2 AS
( SELECT mycol, rownum AS groupid from temp
)
SELECT tablename.mycol, temp2.groupid FROM temp2 JOIN tablename ON temp2.mycol = tablename.mycol
You could also check for a way to implement the tabibitosan method knowing that your column condition is string.

ORACLE join two table with comma separated ids

I have two tables
Table 1
ID NAME
1 Person1
2 Person2
3 Person3
Table 2
ID GROUP_ID
1 1
2 2,3
The IDs in all the columns above refer to the same ID (Example - a Department)
My Expected output (by joining both the tables)
GROUP_ID NAME
1 Person1
2,3 Person2,Person3
Is there a query with which I can achieve this.
It can be done. You shouldn't do it, but perhaps you don't have the power to change the world. (If you have a say in it, you should normalize your table design - in your case, both the input and the output fail the first normal form).
Answering more as good practice for myself... This solution guarantees that the names will be listed in the same order as the id's. It is not the most efficient, and it doesn't deal with id's in the list that are not found in the first table (it simply discards them instead of leaving a marker of some sort).
with
table_1 ( id, name ) as (
select 1, 'Person1' from dual union all
select 2, 'Person2' from dual union all
select 3, 'Person3' from dual
),
table_2 ( id, group_id ) as (
select 1, '1' from dual union all
select 2, '2,3' from dual
),
prep ( id, lvl, token ) as (
select id, level, regexp_substr(group_id, '[^,]', 1, level)
from table_2
connect by level <= regexp_count(group_id, ',') + 1
and prior id = id
and prior sys_guid() is not null
)
select p.id, listagg(t1.name, ',') within group (order by p.lvl) as group_names
from table_1 t1 inner join prep p on t1.id = p.token
group by p.id;
ID GROUP_NAMES
---- --------------------
1 Person1
2 Person2,Person3
select t2.group_id, listagg(t1.name,',') WITHIN GROUP (ORDER BY 1)
from table2 t2, table1 t1
where ','||t2.group_id||',' like '%,'||t1.id||',%'
group by t2.id, t2.group_id
Normalize you data model, this perversion !!! Сomma separated list should not exist in database. Only individual rows per data unit.

Accesing parent identifier in an ordered nested subquery

I need a query to get the value of an item together with the value of the previous item if exists.
I am using the following query (a simplification of the actual):
select v1.value item_value,
nvl(
(
select * from (
select v2.value
from ITEMS v2
where v2.insert_date<v1.insert_date
order by v2.insert_date desc
) where rownum=1
), 0
) as previous_value
from ITEMS v1
where v1.item_id=1234
This query won't work (ORA-00904) because I am using v1.insert_date in an inner select with two levels of nesting.
How can I achieve this with Oracle 11?
I think you can achieve this with analytic function LAG. More info about analytic functions LAG LEAD
I created a sample query:
with items as (
select 1 as value, sysdate as insert_date from dual
union all
select 2 as value, sysdate-1 as insert_date from dual
union all
select 3 as value, sysdate+1 as insert_date from dual
)
select v1.value item_value,
lag(v1.value,1,0) over (order by v1.insert_date desc) as previous_value,insert_date
from ITEMS v1
order by insert_date desc