How can I generate below sequence using Oracle SQL? [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Sequence
1
2
2
3
3
3
4
4
4
4
5
5
5
5
5
and so on ……

Alternatively:
SQL> with temp (col) as
2 (select level
3 from dual
4 connect by level <= &n
5 )
6 select col
7 from temp cross join table(cast(multiset(select level from dual
8 connect by level <= col
9 ) as sys.odcinumberlist))
10 order by col;
Enter value for n: 5
old 4: connect by level <= &n
new 4: connect by level <= 5
COL
----------
1
2
2
3
3
3
4
4
4
4
5
5
5
5
5
15 rows selected.
SQL>

I am thinking two recursive CTEs. One to generate the counts and the other to generate the rows:
with cte(n) as (
select 1
from dual
union all
select n + 1
from cte
where n < 6
),
dups(nn, n) as (
select 1 as nn, n
from cte
union all
select nn + 1, n
from dups
where nn < n
)
select *
from dups;

With Oracle 12 and above you can use LATERAL join. Example:
with gen as (
select level as l
from dual
connect by level < 5
)
select l
from gen,
lateral (
select null
from dual
connect by level <= gen.l
)

You can do it with a single recursive sub-query factoring clause (a.k.a. a CTE) without any joins:
WITH items ( id, seq, max_seq ) AS (
SELECT 1, 1, 6 FROM DUAL
UNION ALL
SELECT CASE WHEN id < seq THEN id + 1 ELSE 1 END,
CASE WHEN id < seq THEN seq ELSE seq + 1 END,
max_seq
FROM items
WHERE id < max_seq
OR seq < max_seq
)
SELECT seq
FROM items;
Which outputs:
| SEQ |
| --: |
| 1 |
| 2 |
| 2 |
| 3 |
| 3 |
| 3 |
| 4 |
| 4 |
| 4 |
| 4 |
| 5 |
| 5 |
| 5 |
| 5 |
| 5 |
| 6 |
| 6 |
| 6 |
| 6 |
| 6 |
| 6 |
db<>fiddle here

Related

Adding a row number respecting the order of each row

I have a table like this
id, period, tag
1 1 A
1 2 A
1 3 B
1 4 A
1 5 A
1 6 A
2 1 A
2 2 B
2 3 B
2 4 B
2 5 B
2 6 A
I would like to add a new column with a ranking, respecting the order of the row given my column 'period' to obtain something like this
id, period, tag rank
1 1 A 1
1 2 A 1
1 3 B 2
1 4 A 3
1 5 A 3
1 6 A 3
2 1 A 1
2 2 B 2
2 3 B 2
2 4 B 2
2 5 B 2
2 6 A 3
What can I do?
I try rank and dense_rank function without any success
And another candidate for CONDITIONAL_CHANGE_EVENT()
less code, and quite effective, too ...!
WITH
input(id,period,tag) AS (
SELECT 1,1,'A'
UNION ALL SELECT 1,2,'A'
UNION ALL SELECT 1,3,'B'
UNION ALL SELECT 1,4,'A'
UNION ALL SELECT 1,5,'A'
UNION ALL SELECT 1,6,'A'
UNION ALL SELECT 2,1,'A'
UNION ALL SELECT 2,2,'B'
UNION ALL SELECT 2,3,'B'
UNION ALL SELECT 2,4,'B'
UNION ALL SELECT 2,5,'B'
UNION ALL SELECT 2,6,'A'
)
SELECT
*
, CONDITIONAL_CHANGE_EVENT(tag) OVER(PARTITION BY id ORDER BY period) + 1 AS rank
FROM input;
-- out id | period | tag | rank
-- out ----+--------+-----+------
-- out 1 | 1 | A | 1
-- out 1 | 2 | A | 1
-- out 1 | 3 | B | 2
-- out 1 | 4 | A | 3
-- out 1 | 5 | A | 3
-- out 1 | 6 | A | 3
-- out 2 | 1 | A | 1
-- out 2 | 2 | B | 2
-- out 2 | 3 | B | 2
-- out 2 | 4 | B | 2
-- out 2 | 5 | B | 2
-- out 2 | 6 | A | 3
-- out (12 rows)
-- out
-- out Time: First fetch (12 rows): 14.823 ms. All rows formatted: 14.874 ms
One method is a cumulative sum based on a lag():
select t.*,
sum(case when prev_tag = tag then 0 else 1 end) over (partition by id order by period) as rank
from (select t.*, lag(tag) over (partition by id order by period) as prev_tag
from t
) t;

Vertica - Union with Group by is possible?

I have two tables like this :
Nu
i j
1 2
1 3
1 4
Nv
i j
2 1
2 5
3 1
3 6
What I want to do is I need to find :
Select j From Nu UNION Select j from Nv) for every Distinct (Nu.i , Nv.i)
Like this :
Nu.i Nv.i v
1 2 2
1 2 3
1 2 4
1 2 1
1 2 5
1 3 2
1 3 3
1 3 4
1 3 1
1 3 6
Is there any way I can query this with Vertica SQL?
I tried :
Select
Nu.i,
Nv.i,
(Select j from Nu UNION Select j from Nv group by Nv.j) as v
from Nu, Nv;
Error :
ERROR 4840: Subquery used as an expression returned more than one row
And :
Select
Nu.i,
Nv.i,
(Select j from Nu UNION Select j from Nv) as v
from Nu, Nv
group by Nu.i, Nv.i;
Error:
Subqueries in the SELECT or ORDER BY are not supported if the subquery
is not part of the GROUP BY
Please, let me know you suggestion.
Your result table is somehow unexpected to me - I can't figure out the rules on how you would want it to be generated.
Nu has 3 rows. Nv has 4 rows. I was thinking of a CROSS JOIN between the two tables, but that would lead to 3 x 4, that's 12 rows. Like so:
WITH
Nu (i,j) AS (
SELECT 1,2
UNION ALL SELECT 1,3
UNION ALL SELECT 1,4
)
,
Nv(i,j) AS (
SELECT 2,1
UNION ALL SELECT 2,5
UNION ALL SELECT 3,1
UNION ALL SELECT 3,6
)
SELECT
Nu.i AS "Nu.i"
, Nv.i AS "Nv.i"
, Nu.j AS "Nu.j"
, Nv.j AS "Nv.j"
FROM Nu CROSS JOIN Nv;
-- out Nu.i | Nv.i | Nu.j | Nv.j
-- out ------+------+------+------
-- out 1 | 2 | 2 | 1
-- out 1 | 2 | 3 | 1
-- out 1 | 2 | 4 | 1
-- out 1 | 2 | 2 | 5
-- out 1 | 2 | 3 | 5
-- out 1 | 2 | 4 | 5
-- out 1 | 3 | 2 | 1
-- out 1 | 3 | 3 | 1
-- out 1 | 3 | 4 | 1
-- out 1 | 3 | 2 | 6
-- out 1 | 3 | 3 | 6
-- out 1 | 3 | 4 | 6
-- out (12 rows)
-- out
-- out Time: First fetch (12 rows): 14.037 ms. All rows formatted: 14.086 ms
But could it be that, seeing this result table, you can figure out the rest by yourself?

SQL: Combinations by Type

I have sets organized by type. I want to find all unique combinations of sets, taking one set from each type. So I start with this:
table1:
row_id type set
1 a 1
2 a 2
3 a 3
4 b 4
5 b 5
6 c 6
and want to get this:
table2:
row_id combo_id type set
1 1 a 1
2 1 b 4
3 1 c 6
4 2 a 2
5 2 b 4
6 2 c 6
7 3 a 3
8 3 b 4
9 3 c 6
10 4 a 1
11 4 b 5
12 4 c 6
13 5 a 2
14 5 b 5
15 5 c 6
16 6 a 3
17 6 b 5
18 6 c 6
The first idea might be to use CROSS JOIN and get something like this:
table3:
row_id combo_id a_set b_set c_set
1 1 1 4 6
2 2 2 4 6
3 3 3 4 6
4 4 1 5 6
5 5 2 5 6
6 6 3 5 6
However, my real data has thousands of types with no upper bound on that number, so I think the setup in table2 is necessary.
I see there are many Stack Overflow questions about SQL combinations. However, none that I found addressed sorting by type, let alone an unbounded number of types.
I'm using PLSQL Developer with Oracle 10g. Thanks!
One method to arrive at your table2 representation would be to use an Up-and-Down hierarchical query:
with table1(row_id, type, val) as (
select 1, 'a', 1 from dual union all
select 2, 'a', 2 from dual union all
select 3, 'a', 3 from dual union all
select 4, 'b', 4 from dual union all
select 5, 'b', 5 from dual union all
select 6, 'c', 6 from dual
), t2 as (
select row_id
, type
, DENSE_RANK() OVER (ORDER BY type desc) type_id
, val
from table1
), Up as (
select row_number() over (partition by CONNECT_BY_ISLEAF
order by SYS_CONNECT_BY_PATH(row_id, ',')) combo_id
, SYS_CONNECT_BY_PATH(row_id, ',') path_id
, prior SYS_CONNECT_BY_PATH(row_id, ',') parent_path_id
, t2.*
, CONNECT_BY_ISLEAF leaf
from t2
connect by type_id = prior type_id+1
start with type_id = 1
), Down as (
select row_number() over (order by CONNECT_BY_ROOT combo_id, type) row_id
, CONNECT_BY_ROOT combo_id combo_id
, type
, val
from Up
connect by path_id = prior parent_path_id
start with leaf = 1
)
select * from Down;
In this solution subquery t2 adds a sequential id for each unique type I've ordered them in reverse order so that the first traversal will end up with type 'a' as the leaf nodes.
In the first tree traversal (subquery Up) I add a unique combo code to all the leaf records for grouping purposes and add the path_id and parent_path_id columns used in the next tree traversal. This is also the stage where all the new rows are generated.
In the second tree traversal (subquery Down) I start at the leaf nodes from the Up traversal and climb back down to the root keeping the root (leaf?) combo_id generated in the prior traversal. No additional rows are generated in this stage since it's a straight shot from the leaf back to the root of the tree.
The final result:
ROW_ID COMBO_ID T VAL
-------- ---------- - ----------
1 1 a 1
2 1 b 4
3 1 c 6
4 2 a 2
5 2 b 4
6 2 c 6
7 3 a 3
8 3 b 4
9 3 c 6
10 4 a 1
11 4 b 5
12 4 c 6
13 5 a 2
14 5 b 5
15 5 c 6
16 6 a 3
17 6 b 5
18 6 c 6
18 rows selected
If you want your Table3 representation you can change the select * from Down to this:
select row_number() over (order by combo_id) row_id
, pvt.*
from (select combo_id, type, val from Down)
pivot (max(val) "SET"
for (type) in ('a' A
,'b' B
,'c' C)) pvt;
Yielding the following result:
ROW_ID COMBO_ID A_SET B_SET C_SET
---------- ---------- ---------- ---------- ----------
1 1 1 4 6
2 2 2 4 6
3 3 3 4 6
4 4 1 5 6
5 5 2 5 6
6 6 3 5 6
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table1 ( "rowid", "type", "set" ) AS
SELECT 1, 'a', 1 FROM DUAL
UNION ALL SELECT 2, 'a', 2 FROM DUAL
UNION ALL SELECT 3, 'a', 3 FROM DUAL
UNION ALL SELECT 4, 'b', 4 FROM DUAL
UNION ALL SELECT 5, 'b', 5 FROM DUAL
UNION ALL SELECT 6, 'c', 6 FROM DUAL
//
CREATE TYPE combo_sets AS OBJECT(
"type" CHAR(1),
idx NUMBER(5,0),
sets SYS.ODCINUMBERLIST
);
//
CREATE TYPE t_combo_sets AS TABLE OF combo_sets;
//
CREATE TYPE combo AS OBJECT(
"rowid" NUMBER(8,0),
"comboid" NUMBER(8,0),
"type" CHAR(1),
"set" NUMBER(5,0)
);
//
CREATE TYPE t_combos AS TABLE of combo;
//
CREATE OR REPLACE FUNCTION get_combos
RETURN t_combos PIPELINED
AS
v_combo_sets t_combo_sets;
i NUMBER(5,0);
r NUMBER(5,0) := 1;
c NUMBER(5,0) := 1;
BEGIN
SELECT combo_sets(
"type",
1,
CAST( COLLECT( "set" ORDER BY "set" ) AS SYS.ODCINUMBERLIST )
)
BULK COLLECT INTO v_combo_sets
FROM table1
GROUP BY "type";
i := 1;
WHILE i <= v_combo_sets.COUNT LOOP
FOR j IN 1 .. v_combo_sets.COUNT LOOP
PIPE ROW(
combo(
r,
c,
v_combo_sets(j)."type",
v_combo_sets(j).sets( v_combo_sets(j).idx )
)
);
r := r + 1;
END LOOP;
c := c + 1;
i := 1;
WHILE i <= v_combo_sets.COUNT AND v_combo_sets(i).idx = v_combo_sets(i).sets.COUNT LOOP
v_combo_sets(i).idx := 1;
i := i + 1;
END LOOP;
IF i <= v_combo_sets.COUNT THEN
v_combo_sets(i).idx := v_combo_sets(i).idx + 1;
END IF;
END LOOP;
RETURN;
END;
//
Query 1:
SELECT *
FROM TABLE( get_combos )
Results:
| rowid | comboid | type | set |
|-------|---------|------|-----|
| 1 | 1 | a | 1 |
| 2 | 1 | b | 4 |
| 3 | 1 | c | 6 |
| 4 | 2 | a | 2 |
| 5 | 2 | b | 4 |
| 6 | 2 | c | 6 |
| 7 | 3 | a | 3 |
| 8 | 3 | b | 4 |
| 9 | 3 | c | 6 |
| 10 | 4 | a | 1 |
| 11 | 4 | b | 5 |
| 12 | 4 | c | 6 |
| 13 | 5 | a | 2 |
| 14 | 5 | b | 5 |
| 15 | 5 | c | 6 |
| 16 | 6 | a | 3 |
| 17 | 6 | b | 5 |
| 18 | 6 | c | 6 |

Create custom Function or Stored Procedure

I have a Hierarchy table with Master_id and Sub_id.
sub_id Master_id
2 1
3 2
4 1
5 3
6 7
I want to create an iterative function or stored procedure (I am not sure I never used any of them before) to create one more column which gives me the primary_master_Column (PMC)
sub_id Master_id PMC
2 1 1
3 2 1
4 1 1
5 3 1
6 7 7
select
Master_id, sub_id,
max(PMC) keep(dense_rank first order by lev desc) as PMC
from
(
select
sub_id as PMC, level lev,
connect_by_root(Master_id) as Master_id,
connect_by_root(sub_id) as sub_id
from your_table
connect by prior sub_id = Master_id
)
group by Master_id, sub_id
fiddle
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE test (sub_id, Master_id) AS
SELECT 2, 1 FROM DUAL
UNION ALL SELECT 3, 2 FROM DUAL
UNION ALL SELECT 4, 1 FROM DUAL
UNION ALL SELECT 5, 3 FROM DUAL
UNION ALL SELECT 6, 7 FROM DUAL;
Query 1:
SELECT t.sub_id,
t.master_id,
CONNECT_BY_ROOT( t.master_id ) AS PMC
FROM test t
LEFT OUTER JOIN
test x
ON ( t.master_id = x.sub_id )
START WITH x.sub_id IS NULL
CONNECT BY PRIOR t.sub_id = t.master_id
Results:
| SUB_ID | MASTER_ID | PMC |
|--------|-----------|-----|
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 5 | 3 | 1 |
| 4 | 1 | 1 |
| 6 | 7 | 7 |
Query 2:
SELECT t.sub_id,
t.master_id,
CONNECT_BY_ROOT( t.master_id ) AS PMC
FROM test t
START WITH NOT EXISTS ( SELECT 'x' FROM test x WHERE t.master_id = x.sub_id )
CONNECT BY PRIOR t.sub_id = t.master_id
Results:
| SUB_ID | MASTER_ID | PMC |
|--------|-----------|-----|
| 2 | 1 | 1 |
| 3 | 2 | 1 |
| 5 | 3 | 1 |
| 4 | 1 | 1 |
| 6 | 7 | 7 |

Select a row X times

I have a very specific sql problem.
I have a table given with order positions (each position belongs to one order, but this isn't a problem):
| Article ID | Amount |
|--------------|----------|
| 5 | 3 |
| 12 | 4 |
For the customer, I need an export with every physical item that is ordered, e.g.
| Article ID | Position |
|--------------|------------|
| 5 | 1 |
| 5 | 2 |
| 5 | 3 |
| 12 | 1 |
| 12 | 2 |
| 12 | 3 |
| 12 | 4 |
How can I build my select statement to give me this results? I think there are two key tasks:
1) Select a row X times based on the amount
2) Set the position for each physical article
You can do it like this
SELECT ArticleID, n.n Position
FROM table1 t JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
) n
ON n.n <= t.amount
ORDER BY ArticleID, Position
Note: subquery n generates a sequence of numbers on the fly from 1 to 100. If you do a lot of such queries you may consider to create persisted tally(numbers) table and use it instead.
Here is SQLFiddle demo
or using a recursive CTE
WITH tally AS (
SELECT 1 n
UNION ALL
SELECT n + 1 FROM tally WHERE n < 100
)
SELECT ArticleID, n.n Position
FROM table1 t JOIN tally n
ON n.n <= t.amount
ORDER BY ArticleID, Position
Here is SQLFiddle demo
Output in both cases:
| ARTICLEID | POSITION |
|-----------|----------|
| 5 | 1 |
| 5 | 2 |
| 5 | 3 |
| 12 | 1 |
| 12 | 2 |
| 12 | 3 |
| 12 | 4 |
Query:
SQLFIDDLEExample
SELECT t1.[Article ID],
t2.number
FROM Table1 t1,
master..spt_values t2
WHERE t1.Amount >= t2.number
AND t2.type = 'P'
AND t2.number <= 255
AND t2.number <> 0
Result:
| ARTICLE ID | NUMBER |
|------------|--------|
| 5 | 1 |
| 5 | 2 |
| 5 | 3 |
| 12 | 1 |
| 12 | 2 |
| 12 | 3 |
| 12 | 4 |