How to generate a start_no and end_no of 1000 split from a table where in it contains numbers from 944900000 to 944999999 using oracle sql - oracle

The table contains numbers from 944900000 to 944999999 and i want to split these numbers into ranges of 1000 each like
944900000 to 944900999 -- 1000
944901000 to 944901999 -- 1000
..
..
944999000 to 944999999 -- 1000
is there any way to generate this through oracle SQL not with PL/SQL

You could also use this.
--Your data
CREATE TABLE your_table(your_column) AS
SELECT 944900000 + LEVEL - 1
FROM dual
CONNECT BY 944900000 + LEVEL < 944999999 + 2
;
--from 944900000 to 944999999
WITH cte AS (
SELECT your_column, CASE WHEN MOD(your_column, 1000) = 0 THEN your_column END start_range
FROM your_table
)
SELECT start_range, end_range
FROM (
SELECT start_range, CASE WHEN start_range IS NOT NULL THEN LEAD(your_column, 999)OVER(ORDER BY your_column) END end_range
FROM cte
)T
WHERE end_range IS NOT NULL /*because of the last execution of lead function in the inline view t*/
GROUP BY start_range, end_range
ORDER BY 1, 2
;

You could use ROW_NUMBER to number all records according to increasing number value. Then, compute a DENSE_RANK using the "group" of increments of 1000 to which each record belongs.
WITH cte AS (
SELECT t.*, ROW_NUMBER OVER (ORDER BY col) rn
FROM yourTable t
),
cte2 AS (
SELECT t.*, DENSE_RANK() OVER (ORDER BY FLOOR(rn / 1000)) dr
FROM cte t
)
SELECT *
FROM cte2
WHERE dr = 2; -- e.g. for 2nd partition of 1000 records

Related

Oracle adding a subquery in a CTE

I have the following setup, which works fine and generates output as expected.
I'm trying to add the locations subquery into the CTE so my output will have a random location_id for each row.
The subquery is straight forward and should work but I am getting syntax errors when I try to place it into the 'data's CTE. I was hoping someone could help me out.
CREATE TABLE employees(
employee_id NUMBER(6),
emp_name VARCHAR2(30)
);
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(1, 'John Doe');
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(2, 'Jane Smith');
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(3, 'Mike Jones');
CREATE TABLE locations AS
SELECT level AS location_id,
'Door ' || level AS location_name
FROM dual
CONNECT BY level <=
with rws as (
select level rn from dual connect by level <= 5 ),
data as ( select e.*,round (dbms_random.value(1,5)
) n from employees e)
select employee_id,
emp_name,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws
join data d on rn <= n
order by employee_id;
-- trying to make this work
with rws as ( select level rn from dual connect by level <= 5 ),
data as ( select e.*, loc.location_id = (
select location_id
from locations order by dbms_random.value()
fetch first 1 row only
),
round (dbms_random.value(1,5)
) n from employees e )
select employee_id,
emp_name,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws
join data d on rn <= n
order by employee_id;
You need to alias the subquery column expression, rather than trying to assign it to a [variable] name. So instead of this:
with rws as ( select level rn from dual connect by level <= 5 ),
data as ( select e.*, loc.location_id = (
select location_id
from locations order by dbms_random.value()
fetch first 1 row only
),
round (dbms_random.value(1,5)
) n from employees e )
you would do this:
with rws as (
select level rn
from dual
connect by level <= 5
),
data as (
select e.*,
(
select location_id
from locations
order by dbms_random.value()
fetch first 1 row only
) as location_id,
round (dbms_random.value(1,5)) as n
from employees e
)
db<>fiddle
But yes, you'll get the same location_id for each row, which probably isn't what you want.
There are probably better ways to avoid it (or to approach whatever you're actually trying to achieve) but one option is to force the subquery to be correlated by adding something like:
where location_id != -1 * e.employee_id
db<>fiddle
although that might be expensive. It's probably worth asking a new question about that specific aspect.
I am getting the same location_id for every employee_id, which I don't want either.
The subquery is in the wrong place then; move it to the main query, and correlate against both ID and n:
with rws as (
select level rn
from dual
connect by level <= 5
),
data as (
select e.*,
round (dbms_random.value(1,5)) as n
from employees e
)
select d.employee_id,
d.emp_name,
(
select location_id
from locations
where location_id != -1 * d.employee_id * d.n
order by dbms_random.value()
fetch first 1 row only
) as location_id,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws r
join data d on r.rn <= d.n
order by d.employee_id;
db<>fiddle
Or move the location part to a new CTE, I suppose, with its own row number; and join that on one of your other generated values.

Systematic Random Sample - Teradata SQL Ast

I need to produce a systematic random sample of (approx) 2500 rows from (approx)230,000 rows with a unique auto generated number on each row.
Is this possible using Teradata SQL ast? (The Sample function produces a simple random sample.)
Thank you for your time.
When there's already a gapless unique row number:
select t.*
from mytable as t
cross join
( select random(1,2500) as rnd ) as dt -- random start row
where rownumber mod 2500 = rnd -- every 2500 rows
Otherwise ROW_NUMBER can be used to create it:
select t.*
from mytable as t
cross join
( select random(1,2500) as rnd ) as dt
qualify ROW_NUMBER() OVER (ORDER BY whatever_determines_your_order) mod 2500 = rnd
select rank() over(order by $primary_index_key), t1.*
FROM
(select * from $table_name
sample 2500) t1
Assistant would do that, and so would any other client.
Same approach can be used to generate winning Powerball numbers.
From your comment, I think that you cannot do it on the fly. You need to generate some table first that would contain Step# and step_value, for example:
[1,2500],[2,5000],...[x,x*2500]
Than you should join this table to your query and limit row numbers by the logic: rn = random_seed + step_value.
It will look like this:
select
from (
select t1.*
, row_number() over("ordering logic") as rn
from my_table
) as t1
, (select random(1,2500) as random_seed) as seed --so it will be generated only once
where exists (
select 1 from sampling_table as t2
where t1.rn = t2.step_value + seed.random_seed
)

How can i avoid rownum as a column when limiting records in oracle?

when i run the query:
select *
from ( select a.*,
ROWNUM rnum
from ( select *
from test
order by null ) a
where ROWNUM <= 2000 )
where rnum >=1
I'm getting all the columns along with rownum as a separate column which I don't want, How to achieve this or is there any way to limit records?
Since the final filter is for ROWNUM >= 1 (which will always be true), you can eliminate that and just use:
select *
from (
select *
from test
order by null
)
where ROWNUM <= 2000
(Note: ORDER BY NULL will apply a non-deterministic ordering.)
If you want to specify a different starting row then you will need to specify the columns you want to return:
select col_1,
col_2,
-- ...
col_n
from (
select a.*,
ROWNUM rnum
from (
select *
from test
order by null
) a
where ROWNUM <= 2000
)
WHERE rnum > 1000
In Oracle 12c you can use:
SELECT *
FROM test
ORDER BY NULL
FETCH FIRST 2000 ROWS ONLY;
or
SELECT *
FROM test
ORDER BY NULL
OFFSET 1000 ROWS FETCH NEXT 1000 ROWS ONLY;

Ora-00932 - expected NUMBER got -

I have been running the below query without issue:
with Nums (NN) as
(
select 0 as NN
from dual
union all
select NN+1 -- (1)
from Nums
where NN < 30
)
select null as errormsg, trunc(sysdate)-NN as the_date, count(id) as the_count
from Nums
left join
(
SELECT c1.id, trunc(c1.c_date) as c_date
FROM table1 c1
where c1.c_date > trunc(sysdate) - 30
UNION
SELECT c2.id, trunc(c2.c_date)
FROM table2 c2
where c2.c_date > trunc(sysdate) -30
) x1
on x1.c_date = trunc(sysdate)-Nums.NN
group by trunc(sysdate)-Nums.NN
However, when I try to pop this in a proc for SSRS use:
procedure pr_do_the_thing (RefCur out sys_refcursor)
is
oops varchar2(100);
begin
open RefCur for
-- see above query --
;
end pr_do_the_thing;
I get
Error(): PL/SQL: ORA-00932: inconsistent datatypes: expected NUMBER got -
Any thoughts? Like I said above, as a query, there is no issue. As a proc, the error appears at note (1) int eh query.
This seems to be bug 18139621 (see MOS Doc ID 2003626.1). There is a patch available, but if this is the only place you encounter this, it might be simpler to switch to a hierarchical query:
with Nums (NN) as
(
select level - 1
from dual
connect by level <= 31
)
...
You could also calculate the dates inside the CTE (which also fails with a recursive CTE):
with Dates (DD) as
(
select trunc(sysdate) - level + 1
from dual
connect by level <= 31
)
select null as errormsg, DD as the_date, count(id) as the_count
from Dates
left join
(
SELECT c1.id, trunc(c1.c_date) as c_date
FROM table1 c1
where c1.c_date > trunc(sysdate) - 30
UNION
SELECT c2.id, trunc(c2.c_date)
FROM table2 c2
where c2.c_date > trunc(sysdate) -30
) x1
on x1.c_date = DD
group by DD;
I'd probably organise it slightly differently, so the subquery doesn't limit the date range directly:
with dates (dd) as
(
select trunc(sysdate) - level + 1
from dual
connect by level <= 31
)
select errormsg, the_date, count(id) as the_count
from (
select null as errormsg, d.dd as the_date, c1.id
from dates d
left join table1 c1 on c1.c_date >= d.dd and c1.c_date < d.dd + 1
union all
select null as errormsg, d.dd as the_date, c2.id
from dates d
left join table2 c2 on c2.c_date >= d.dd and c2.c_date < d.dd + 1
)
group by errormsg, the_date;
but as always with these things, check the performance of each approach...
Also notice that I've switched from union to union all. If an ID could appear more than once on the same day, in the same table or across both tables, then the counts will be different - you need to decide whether you want to count them once or as many times as they appear. That applies to your original query too.

Retrieving page that contains specific row

I have a procedure that returns multiple rows on some criteria and in specific order. These rows are separated into few pages (50 rows per page).
How can I retrieve all rows from page having some specific row.
I've created a query the query that do this work, but it is not optimized and have huge impact on performance. Help me please to optimize it or give an alternative to it:
select *
from
(
select file_id, row_number() over (order by rownum) rn
from my_table
)
where trunc(rn/50) = (
select trunc(rn/50) from
(select t.*, rownum rn from my_table t)
where file_id = 29987);
You have to adjust it a little...
with tab as
(
-- the
-- row_number() over (order by rownum) rn
-- should be here
select level + 1000 as val
, level/50 as rn_50
from dual
connect by
level < 140
)
, val as
(
select rn_50
from tab
where val = 1004 -- pg 1
--where val = 1051 -- pg 2
--where val = 1101 -- pg 3
)
select *
from tab t
where rn_50 >= (select floor(rn_50) from val)
and rn_50 <= (select ceil (rn_50) from val)
;

Resources