Generate series of integers with random start and end SQL Oracle - sql
I am trying to generate a series of integers that go from a random start-point until a random (greater) end-point. Furthermore, I would like to do this as a window function, so I could use this in a OVER (PARTITION BY ) statement.
Basically I'm trying to select random hours (from 1-24), but in a random way and also consecutively, and do this for each client (which is why I suggest an OVER (PARTITION BY client) statement, but I'm open for other ideas.
I am trying to use:
SELECT
T1.HOURS
FROM (
SELECT
LEVEL HOURS
FROM DUAL
CONNECT BY
LEVEL <= 24
) T1,
(
SELECT
INIT,
LEAST(INIT + LENGTH, 24) FIN
FROM (
SELECT
ROUND(DBMS_RANDOM.VALUE(1, 24)) INIT,
ROUND(DBMS_RANDOM.VALUE(1, 24)) LENGTH
FROM DUAL
) T0
) T2
WHERE
T1.HOURS >= T2.INIT AND
T1.HOURS <= T2.FIN;
But the result is unfortunately non-consecutive orders.
|hours|
|-----|
|17|
|18|
|20|
|24|
The code is simply nor working because the table T0 (which is the one that filters the initial INIT and final FIN value) is being replicated for each row.
This is a desired result:
client
hours
1
4
1
5
1
6
1
7
2
14
2
15
3
13
3
14
3
15
3
16
3
17
3
18
3
19
3
20
3
21
In the desired result a consecutive list is selected for each client, with a random start and end point.
In Oracle, you can use a correlated LATERAL join:
SELECT c.id,
h.hours
FROM ( SELECT id,
FLOOR(DBMS_RANDOM.VALUE(1, 25)) AS bound1,
FLOOR(DBMS_RANDOM.VALUE(1, 25)) AS bound2
FROM clients
) c
CROSS JOIN LATERAL (
SELECT LEAST(bound1, bound2) + LEVEL - 1 AS hours
FROM DUAL
CONNECT BY LEVEL <= ABS(bound1 - bound2) + 1
) h;
Then, for the sample data:
CREATE TABLE clients (id) AS
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 3;
May (randomly) output:
ID
HOURS
1
7
1
8
1
9
1
10
2
19
2
20
2
21
2
22
2
23
2
24
3
6
3
7
3
8
3
9
3
10
3
11
3
12
3
13
3
14
3
15
3
16
fiddle
Related
Is it possible to use a aggregate function over partition by as a case condition in SQL?
Problem statement is to calculate median from a table that has two columns. One specifying a number and the other column specifying the frequency of the number. For e.g. Table "Numbers": Num Freq 1 3 2 3 This median needs to be found for the flattened array with values: 1,1,1,2,2,2 Query: with ct1 as (select num,frequency, sum(frequency) over(order by num) as sf from numbers o) select case when count(num) over(order by num) = 1 then num when count(num) over (order by num) > 1 then sum(num)/2 end median from ct1 b where sf <= (select max(sf)/2 from ct1) or (sf-frequency) <= (select max(sf)/2 from ct1) Is it not possible to use count(num) over(order by num) as the condition in the case statement?
Find the relevant row / 2 rows based of the accumulated frequencies, and take the average of num. The example and Fiddle will also show you the computations leading to the result. If you already know that num is unique, rowid can be removed from the ORDER BY clauses with t1 as ( select t.* ,nvl(sum(freq) over (order by num,rowid rows between unbounded preceding and 1 preceding),0) as freq_acc_sum_1 ,sum(freq) over (order by num, rowid) as freq_acc_sum_2 ,sum(freq) over () as freq_sum from t ) select t1.* ,case when freq_sum/2 between freq_acc_sum_1 and freq_acc_sum_2 then 'V' end as relevant_record from t1 order by num, rowid Fiddle Example: ID NUM FREQ FREQ_ACC_SUM_1 FREQ_ACC_SUM_2 FREQ_SUM RELEVANT_RECORD 7 8 1 0 1 18 5 10 1 1 2 18 1 29 3 2 5 18 6 31 1 5 6 18 3 33 2 6 8 18 4 41 1 8 9 18 V 9 49 2 9 11 18 V 2 52 1 11 12 18 8 56 3 12 15 18 10 92 3 15 18 18 MEDIAN 45 Fiddle for 1M records
You can find the one (or two) middle value(s) and then average: SELECT AVG(num) AS median FROM ( SELECT num, freq, SUM(freq) OVER (ORDER BY num) AS cum_freq, (SUM(freq) OVER () + 1)/2 AS median_freq FROM table_name ) WHERE cum_freq - freq < median_freq AND median_freq < cum_freq + 1 Or, expand the values using a LATERAL join to a hierarchical query and then use the MEDIAN function: SELECT MEDIAN(num) AS median FROM table_name t CROSS JOIN LATERAL ( SELECT LEVEL FROM DUAL WHERE freq > 0 CONNECT BY LEVEL <= freq ) Which, for the sample data: CREATE TABLE table_name (Num, Freq) AS SELECT 1, 3 FROM DUAL UNION ALL SELECT 2, 3 FROM DUAL; Outputs: MEDIAN 1.5 (Note: For your sample data, there are 6 items, an even number, so the MEDIAN will be half way between the value of 3rd and 4rd items; so half way between 1 and 2 = 1.5.) db<>fiddle here
SQL for a generated table with column 1 a sequence of numbers and column 2 a running sum
What would be the SQL (standard, or any major variant) to produce a table like the following? 1 1 -- 1 2 3 -- 2+1 3 6 -- 3+2+1 4 10 -- 4+3+2+1 5 15 -- 5+4+3+2+1 6 21 -- 6+5+4+3+2+1 ... ... The second column is the sum of the numbers in the first. I couldn't get past this: select rownum from all_objects where rownum <= 10; Which produces column 1 (PL/SQL) Tried to think on the following lines but clearly it is wrong, even syntactically: select rownum, count(t2.rownum) from (select sum(rownum) from all_objects where rownum <= 10) t2, all_objects where rownum <= 10;
It is simple math: select rownum, rownum * (rownum + 1) / 2 from all_objects where rownum <= 10;
You don't need to hit the all_objects view; you could use a hierarchical query: select level as position, sum(level) over (order by level) as running_sum from dual connect by level <= 10; POSITION RUNNING_SUM ---------- ----------- 1 1 2 3 3 6 4 10 5 15 6 21 7 28 8 36 9 45 10 55 or using #forpas' arithmetic-series method: select level as position, level * (level + 1) / 2 as running_sum from dual connect by level <= 10; POSITION RUNNING_SUM ---------- ----------- 1 1 2 3 3 6 4 10 5 15 6 21 7 28 8 36 9 45 10 55 Or recursive subquery factoring (11gR2+): with rcte (position, running_sum) as ( select 1, 1 from dual union all select position + 1, running_sum + position + 1 from rcte where position < 10 ) select * from rcte order by position; POSITION RUNNING_SUM ---------- ----------- 1 1 2 3 3 6 4 10 5 15 6 21 7 28 8 36 9 45 10 55
You are looking for a cumulative sum: select rownum, sum(rownum) over (order by rownum) from all_objects where rownum <= 10; I wasn't sure this would actually work on rownum, but it does.
SQL Recursive CTE unexpectedly returns alternating sets
I am trying to get the use recursive CTE to repeat the same pattern over and over, resetting when "Scenario" increases in value. RowNumber repeats 1-21 (as desired), but whenever "Scenario" is an even number, there are too few items in the "Vals" column to feed into "Value". I can't figure out which part of the code is causing me to be 1 short for only even Scenarios. Below are the results of the code I'm using at the bottom. Scenario RowNumber Value Vals 1 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 6 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 7 A A,A,A,A,A,A,A,A,A,A,A,A,B,C 1 8 A A,A,A,A,A,A,A,A,A,A,A,B,C 1 9 A A,A,A,A,A,A,A,A,A,A,B,C 1 10 A A,A,A,A,A,A,A,A,A,B,C 1 11 A A,A,A,A,A,A,A,A,B,C 1 12 A A,A,A,A,A,A,A,B,C 1 13 A A,A,A,A,A,A,B,C 1 14 A A,A,A,A,A,B,C 1 15 A A,A,A,A,B,C 1 16 A A,A,A,B,C 1 17 A A,A,B,C 1 18 A A,B,C 1 19 A B,C 1 20 B C 1 21 C 2 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 5 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 6 A A,A,A,A,A,A,A,A,A,A,A,B,B,C 2 7 A A,A,A,A,A,A,A,A,A,A,B,B,C 2 8 A A,A,A,A,A,A,A,A,A,B,B,C 2 9 A A,A,A,A,A,A,A,A,B,B,C 2 10 A A,A,A,A,A,A,A,B,B,C 2 11 A A,A,A,A,A,A,B,B,C 2 12 A A,A,A,A,A,B,B,C 2 13 A A,A,A,A,B,B,C 2 14 A A,A,A,B,B,C 2 15 A A,A,B,B,C 2 16 A A,B,B,C 2 17 A B,B,C 2 18 B B,C 2 19 B C 2 20 C 2 21 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,C 3 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 4 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 5 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 6 A A,A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 7 A A,A,A,A,A,A,A,A,A,A,A,B,C,C 3 8 A A,A,A,A,A,A,A,A,A,A,B,C,C 3 9 A A,A,A,A,A,A,A,A,A,B,C,C 3 10 A A,A,A,A,A,A,A,A,B,C,C 3 11 A A,A,A,A,A,A,A,B,C,C 3 12 A A,A,A,A,A,A,B,C,C 3 13 A A,A,A,A,A,B,C,C 3 14 A A,A,A,A,B,C,C 3 15 A A,A,A,B,C,C 3 16 A A,A,B,C,C 3 17 A A,B,C,C 3 18 A B,C,C 3 19 B C,C 3 20 C C 3 21 C 4 1 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 2 A A,A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 3 A A,A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 4 A A,A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 5 A A,A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 6 A A,A,A,A,A,A,A,A,A,A,B,B,B,C 4 7 A A,A,A,A,A,A,A,A,A,B,B,B,C 4 8 A A,A,A,A,A,A,A,A,B,B,B,C 4 9 A A,A,A,A,A,A,A,B,B,B,C 4 10 A A,A,A,A,A,A,B,B,B,C 4 11 A A,A,A,A,A,B,B,B,C 4 12 A A,A,A,A,B,B,B,C 4 13 A A,A,A,B,B,B,C 4 14 A A,A,B,B,B,C 4 15 A A,B,B,B,C 4 16 A B,B,B,C 4 17 B B,B,C 4 18 B B,C 4 19 B C 4 20 C This is the code I used to generate the above sample. Where am I going wrong? CREATE TABLE #temp3 ( Scenario INT ,Vals VARCHAR(64) ,LEN INT ) ; WITH vals AS ( SELECT v.* FROM (VALUES ('A'), ('B'), ('C')) v(x) ), CTE AS ( SELECT CAST('A' AS VARCHAR(MAX)) AS STR, 0 AS LEN UNION ALL SELECT (CTE.STR + ',' + vals.x), CTE.LEN + 1 FROM CTE JOIN vals ON vals.x >= RIGHT(CTE.STR, 1) WHERE CTE.LEN < 19 ) INSERT INTO #temp3 SELECT ROW_NUMBER() OVER(ORDER BY STR + ',C') AS Scenario ,STR + ',C' AS Vals ,LEN FROM CTE WHERE STR + 'C' LIKE '%B%' AND LEN = 19 ; -- Split strings created above into individual characters WITH cte(Scenario, Value, Vals) AS ( SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY Scenario) RowNumber ,Value ,Vals FROM cte t
I'm not exactly sure what the problem you are describing is, but the ROW_NUMBER() should use an ORDER BY clause that completely orders the rows in each partition. When you use "PARTITION BY Scenario ORDER BY Scenario" the order in which the ROW_NUMBER() values are assigned is undefined. Try something like WITH cte(Scenario, depth, Value, Vals) AS ( SELECT Scenario, 0 depth ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) AS Value ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') AS Vals FROM #temp3 UNION ALL SELECT Scenario, depth+1 ,CAST(LEFT(Vals, CHARINDEX(',',Vals+',')-1) AS VARCHAR(10)) ,STUFF(Vals, 1, CHARINDEX(',',Vals+','), '') FROM cte WHERE Vals > '' ) SELECT Scenario ,depth ,ROW_NUMBER() OVER (PARTITION BY Scenario ORDER BY depth ) RowNumber ,Value ,Vals FROM cte t
How to group/List all nodes of a undirected graph using teradata sql
I have data for many diff. set of undirected graphs in a table (like adjacent list relationship, one node is connected which all node) and I need to group all individual undirected graphs. Eg: all nodes of the particular undirected graphs will be in a group & group name will be the min. of the node. sel d.adj_node, min(d.adj_node) Over (Partition By a.node) as grp table a left join table b on a.adj_node=b.node left join table c on b.adj_node=c.node left join table d on c.adj_node=d.node; Now, I am doing a self-join for 4,5 times and then on top that query doing partitioning it to get the desired output. But doing self-join 4 5 times is creating performance issue. So, need some recursive sql, stored procedure or some other logic to do the same for all levels. Input Data & Required Output will be like this link Looking for some suggestions. Input Table node adj_node 1 2 2 1 2 3 2 5 2 6 2 7 3 2 3 4 4 3 4 5 4 6 4 7 5 2 5 4 6 2 6 4 6 8 7 2 7 4 8 6 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 10 11 11 10 11 13 11 14 12 13 12 14 13 11 13 12 13 14 14 11 14 12 14 13 10 10 11 11 12 12 13 13 14 14 Output node grp 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 10 10 11 10 12 10 13 10 14 10
I just remembered that I did something similar before using updates on a temp table. The best way to implement this would be a Stored Procedure with a loop in it: CREATE VOLATILE TABLE vt_tab AS ( SELECT DISTINCT NODE , adj_node, NODE AS grp FROM tab AS t1 WHERE adj_node <> NODE ) WITH DATA ON COMMIT PRESERVE ROWS ; -- REPEAT this update UNTIL activity_count = 0 UPDATE vt_tab FROM ( SELECT t2.NODE, MIN(t1.grp) AS mingrp FROM vt_tab AS t1 JOIN vt_tab AS t2 ON t1.adj_node = t2.NODE AND t1.grp < t2.grp GROUP BY t2.NODE ) x SET grp = mingrp WHERE vt_tab.NODE = x.NODE ; --get the final result SEL DISTINCT NODE,grp FROM vt_tab ORDER BY 1 ; Recursion might be possible, but there's a high probability that it will blow your spool because you need repeated m:n joins and only the final Select allows to reduce the result rows.
A solution with a recursive CTE: with cte as ( select node as node, node as grp from Tabl_1 Union all select C.node, T.adj_node from CTE C inner join Tabl_1 T on C.grp = T.node where T.adj_node < C.grp ) select node, MIN(grp) as grp from cte group by node order by node == EDIT 1 == Here is a new version to reflect your point. with cte as ( select node as node, node as grp, ',' + CAST(node as varchar(max)) + '-' + CAST(node as varchar(max)) + ',' as pair from Tabl_1 Union all select C.node, T.adj_node, C.pair + CAST(C.node as varchar(max)) + '-' + CAST(T.adj_node as varchar(max)) + ',' from CTE C inner join Tabl_1 T on C.grp = T.node where C.pair not like '%,' + CAST(C.node as varchar(max)) + '-' + CAST(T.adj_node as varchar(max)) + ',%' ) select node, MIN(grp) as grp from cte group by node order by node
Select Data based on Sum of another columns value
I have a Table with Data as RowIndex Id TicketCount 1 23 1 2 25 2 3 3 1 4 14 1 5 16 1 6 18 1 7 1 1 8 6 1 9 15 1 ===> at this row the sum of Ticket Count is 10 10 22 1 11 27 1 12 24 1 13 26 2 14 9 1 15 19 1 From this Data I want to Select All Records where The Sum of Ticket Count will be equal to 10(user input value) In the Given data I want to Select all Records till Row Index 9. Output should be: RowIndex Id TicketCount 1 23 1 2 25 2 3 3 1 4 14 1 5 16 1 6 18 1 7 1 1 8 6 1 9 15 1
SQL Server 2008 doesn't have the cumulative sum function. I implement it using a correlated subquery: select RowIndex, Id, TicketCount from (select t.*, (select sum(TicketCount) from t t2 where t2.RowIndex <= t.RowIndex ) as cumTicketCount from t ) t where cumTicketCount <= 10; In SQL Server 2012, you can phrase this using a window function: select RowIndex, Id, TicketCount from (select t.*, sum(TicketCount) over (order by RowIndex) as CumTicketCount from t ) t where cumTicketCount <= 10;
You can do it using recursive CTE: WITH RCTE AS ( SELECT *, TicketCount AS Total FROM Table1 WHERE RowIndex = 1 UNION ALL SELECT t.*, r.Total + t.TicketCount FROM RCTE r INNER JOIN Table1 t ON r.RowIndex + 1 = t.RowIndex WHERE r.Total + t.TicketCount <= 10 --your input value ) SELECT * FROM RCTE SQLFiddle DEMO