Oracle sql to split data into ranges based on count - sql

I am working on a requirement where I need to populate a table with range based on the records count from input
Sample O/p if the input has 8954 records :- The # of records from input will keep changing, where as the split based on 3K records is constant.
Entity start end
abc 1 3000
abc 3001 6000
abc 6001 8954
I have tried using hierarchical query but it fails after 1 million records due to memory issue.

You need to use hierarchy query to generate the records as follows:
SQL> SELECT
2 'abc' AS ENTITY,
3 ( LEVEL - 1 ) * 3000 + 1 as st,
4 LEAST(LEVEL * 3000, 8954) as en
5 FROM
6 DUAL
7 CONNECT BY
8 LEVEL <= CEIL(8954 / 3000);
ENT ST EN
--- ---------- ----------
abc 1 3000
abc 3001 6000
abc 6001 8954
SQL>
replace 8954 with actual value in above query.

Related

How to copy a table but randomise the rows with respect to one of the columns?

Does anyone know how can I mix up the data order while insert the records into another table in SQL?
Example:
I have 2 tables, Table A and Table B, I would like to insert the record from Table A to Table B, how ever I would like the records mix up while insert into Table B insert of follow the order in Table A. Will it be possible to do it in SQL?
Table A:
ID Postcode Total
1 3000 10
2 3000 20
3 3000 5
4 3001 10
5 3001 6
6 3002 6
7 3002 9
8 3002 10
9 3003 85
10 3004 1
After insert into Table B (the records randomly mixed up):
ID Postcode Total
1 3001 10
2 3002 20
3 3000 5
4 3003 85
5 3002 6
6 3001 6
7 3002 9
8 3000 20
9 3000 10
10 3004 1
Yes you can:
INSERT INTO TableB
SELECT *
FROM (SELECT TOP 10 * FROM TableA ORDER BY NEWID()) AS tmp
Make sure TableB does not have a clustered key or else it won't work. Change TOP 10 to the number of rows you have in TableA.
Edit: a commenter pointed that the original version won't work in SQL Server 2012 and above. In that case you need a more heavy handed version (updated).

How to assign the Parent Group IDs to each record of a hierarchical table in Oracle 11g?

Based on the following sample hierarchical data that exists within the TECH_VALUES table, how can I create a view, say TECH_VALUES_VW that will take this same data but have an additional column, namely GROUP_ID_PARENT that will show the group id where the parent group id is 0 against the row that child belongs to, see new column data sample:
ID GROUP_ID LINK_ID PARENT_GROUP_ID TECH_TYPE GROUP_ID_PARENT
------- ------------- ------------ -------------------- ---------- ---------------
1 100 LETTER_A 0 100
2 200 LETTER_B 0 200
3 300 LETTER_C 0 300
4 400 LETTER_A1 100 A 100
5 500 LETTER_A2 100 A 100
6 600 LETTER_A3 100 A 100
7 700 LETTER_AA1 400 B 100
8 800 LETTER_AAA1 700 C 100
9 900 LETTER_B2 200 B 200
10 1000 LETTER_BB5 900 B 200
12 1200 LETTER_CC1 300 C 300
13 1300 LETTER_CC2 300 C 300
14 1400 LETTER_CC3 300 A 300
15 1500 LETTER_CCC5 1400 A 300
16 1600 LETTER_CCC6 1500 C 300
17 1700 LETTER_BBB8 900 B 200
18 1800 LETTER_B 0 1800
19 1900 LETTER_B2 1800 B 1800
20 2000 LETTER_BB5 1900 B 1800
21 2100 LETTER_BBB8 1900 B 1800
So based on the above, I want to take the table definition:
Table Name: TECH_VALUES:
ID,
GROUP_ID,
LINK_ID
PARENT_GROUP_ID,
TECH_TYPE
and create a new view
View Name: TECH_VALUES_VW:
ID,
GROUP_ID,
LINK_ID
PARENT_GROUP_ID,
TECH_TYPE,
GROUP_ID_PARENT
based on the above sample data from the TECH_VALUES table.
I am looking to create a new query to build this new view which will only use the GROUP_IDs for the PARENT_GROUP_IDs that are 0 for each row.
Updated
Just to make things a whole lot clearer of exactly what I am after is if I take out only the records where the PARENT_GROUP_ID is 0 within the TECH_VALUES table, i.e.
ID GROUP_ID LINK_ID PARENT_GROUP_ID
------- ------------- ------------ --------------------
1 100 LETTER_A 0
2 200 LETTER_B 0
3 300 LETTER_C 0
18 1800 LETTER_B 0
Using just the GROUP_ID values for these 4 records, assign this GROUP_ID to all of the children records for each of these parent link ids as a new column in the TECH_VALUES_VW as well as to the original link ids (where PARENT_GROUP_ID is 0) as shown in the sample data set above.
If I understood your question correctly, then this might be what you're after:
CREATE OR REPLACE VIEW tech_values_vw
AS
SELECT TV.*,
CASE WHEN LEVEL = 1 THEN group_id ELSE connect_by_root(group_id) END AS group_id_parent
FROM tech_values TV
START WITH parent_group_id = 0
CONNECT BY PRIOR group_id = parent_group_id
;

Find sequential child rows that have amounts which add up to parent row's amount

I have a table like following
ID DATE ACCT TYPE AMOUNT SEQ CHK# TRC
1 6/5/2014 1234 C 10,000 1 1001
2 6/5/2014 3333 3,000 2 123 1002
3 6/5/2014 4444 5,000 3 234 1003
4 6/5/2014 5555 2,000 4 345 1004
5 6/5/2014 2345 C 3,000 1 1007
6 6/5/2014 5555 2,500 2 255 1008
7 6/5/2014 7777 500 3 277 1009
8 6/6/2014 1234 C 5,000 1 2001
9 6/6/2014 7777 3,000 2 278 2002
10 6/6/2014 8888 2,000 3 301 2003
The rows with TYPE = C are parent rows to the child rows that follow sequentially.
The parent rows do not have CHK# and child rows do have CHK#. Each
parent row has seq# = 1 and child rows have sequential numbers. (if it
matters) From above table, row ID 1 is the parent row to the rows with
ID 2 ~ 4. The AMOUNT on the child rows add up to the parent row's
amount.
Querying for transaction for date of '6/5/2014' on account # 2345 with
the amount of 3,000 - result should be rows with ID 6 and 7.
Is such query possible using MS-SQL 2008? If so, could you let me
know?
Well, based on the data that you have, you can use the id column to find the rows that you want. First, look for the one that has the check in that amount. The look for the subsequent ids with the same group. How do you define the group? That is easy. Take the difference between id and seq. This difference is constant for the parent and child rows.
So, here is goes:
select t.*
from table t
where (t.id - t.seq) = (select t2.id - t2.seq
from table t2
where t2.type = 'C' and
t2.acct = '2345' and
t2.date = '6/5/2014'
) and
t.type is null;

Using sequences to create group ID

I'm attempting to create group_ids based on a set of item_ids. The only indication that the item_ids are part of a single group is the fact that item_ids are sequential. For example, based on the first two columns below, the output I want is the third:
item item_id group_id
ABC 282 2
ABC 283 2
ABC 284 2
ABC 285 2
ABC 051 3
ABC 052 3
ABC 189 4
ABC 231 5
ABC 232 5
ABC 233 5
ABC 234 5
ABC 247 6
ABC 248 6
ABC 249 6
ABC 250 6
ABC 091 7
ABC 092 7
The group_id doesn't necessarily have to be sequential itself, it only has to be unique. I attempted this with the following code:
create sequence seq
start with 1
minvalue 1
increment by 1
cache 20;
select seq.nextval from dual; --to initialize the sequence
select
item,
item_id,
case when diff = 1 then seq.currval else seq.nextval end group_id
from
(
select
item,
item_id,
(id - lag(id, 1, 0) over (order by 1) diff
from
(
select
item,
item_id
from
table
)
);
But get the following output:
item item_id group_id
ABC 282 2
ABC 283 3
ABC 284 4
ABC 285 5
ABC 051 6
ABC 052 7
ABC 189 8
ABC 231 9
ABC 232 10
ABC 233 11
ABC 234 12
ABC 247 13
ABC 248 14
ABC 249 15
ABC 250 16
ABC 091 17
ABC 092 18
When looking for the cause of the problem, I found an excellent explanation by user ShannonSeverance that details why my solution won't work. However, it didn't provide any suggestions on how to move forward.
Does anyone have any ideas?
You have a problem, because SQL tables are inherently unordered. The following "should" logically work, although it won't in practice:
select ii.*, (item_id - rownum) as grp_id
from item_ids ii;
A sequence of item_ids in order minus the row number is constant. You can use that for a group, at least for a given item. To handle multiple items, concatenate the values together:
select ii.*, item||'-'||(item_id - rownum) as grp_id
from item_ids ii;
To really make this work, you need to add an order by -- this guarantees the ordering of the results from the select. This might work, assuming that there are "holes" between the groups:
select ii.*, item||'-'||(item_id - rownum) as grp_id
from item_ids ii
order by item, item_id;
Otherwise, you need some other column to determine the proper ordering for the items.

Access SQL - Select only the last sequence

I have a table with an ID and multiple informative columns. Sometimes however, I can have multiple data for an ID, so I added a column called "Sequence". Here is a shortened example:
ID Sequence Name Tel Date Amount
124 1 Bob 873-4356 2001-02-03 10
124 2 Bob 873-4356 2002-03-12 7
124 3 Bob 873-4351 2006-07-08 24
125 1 John 983-4568 2007-02-01 3
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
So, I would like to obtain only these lines:
124 3 Bob 873-4351 2006-07-08 24
125 2 John 983-4568 2008-02-08 13
126 1 Eric 345-9845 2010-01-01 18
Anyone could give me a hand on how I could build a SQL query to do this ?
Thanks !
You can calculate the maximum sequence using group by. Then you can use join to get only the maximum in the original data.
Assuming your table is called t:
select t.*
from t join
(select id, MAX(sequence) as maxs
from t
group by id
) tmax
on t.id = tmax.id and
t.sequence = tmax.maxs