How to insert multiple rows from one column? - sql

I want to insert multiple rows from one column by splitting column value. But I have to do that without cursors because of performance issues.
Every value is splitted to 6 chars length values. Then these values also splitted to 3, 1 and 2 chars length values to insert different columns in table B.
I think giving a sample will clarify my question:
Table A
ID Value
1 ABCDEFGHJKLM
2 NOPRST
3 NULL VALUE
I want to insert these values into table B like this format
Table B
ID Value1 Value2 Value3
1 ABC D EF
1 GHJ K LM
2 NOP R ST

Supposing 600(100 rows) as maximum length of value:
insert into tableB
select id, substr(value,n*6+1,3), substr(value,n*6+4,1), substr(value,n*6+5,2)
from tableA
join (select level-1 as n from dual connect by level <= 100)
on length(value) > n*6;
see Sqlfiddle.

select ID,
SUBSTR(value,number*6+1,3),
SUBSTR(value,number*6+4,1),
SUBSTR(value,number*6+5,2)
from yourtable,
(select 0 as number union select 1 union select 2 union select 3 union select 4
union select 5 union select 6) as numbers
/* etc up to the max length of your string /6 */
where LEN(value)>number*6

try this:
Please convert it to ORACLE SQL..
Even though, its using a while loop, its doing bulk inserts..and the loop is executed as per the length of maximun length of value in the table
declare #max_len int=0;
declare #counter int=0;
declare #col_index int=1;
select #max_len=MAX(len(Value)) from TableA
while (#max_len/6 > #counter)
begin
set #counter=#counter+1
Insert into TableB
select ID,substring(Value,#col_index,3),
substring(Value,#col_index+3,1),
substring(Value,#col_index+4,2)
from TableA where substring(Value,#col_index,3) is not null
set #col_index=#col_index+6
end

Related

SQL clone/replicate records within same table with a condition

I have a table and i would like to replicate/clone records within the same table. However i would like to do that with a condition. And the condition is i have a column called recordcount with numeric values. For example Row 1 can take on a value of recordcount say 7, then i would like my row 1 to be replicated 7 times. Row 2 could take on a value say 9 then i would like row 2 to be replicated 9 times.
Any help is appreciated. Thank you
What you can do (and I'm pretty sure it's not a best practice),
Is to hold a table with just numbers, which has rowcount that correspond to the numeric value.
Join that with your table, and project your table only.
Example:
create table nums(x int);
insert into nums select 1;
insert into nums select 2;
insert into nums select 2;
insert into nums select 3;
insert into nums select 3;
insert into nums select 3;
create table t (txt varchar(10) , recordcount int);
insert into t select 'A',1;
insert into t select 'B',2;
insert into t select 'C',3;
select t.*
from t
inner join nums
on t.recordcount = nums.x
order by 1
;
Will project:
"A",1
"B",2
"B",2
"C",3
"C",3
"C",3

SQL Server match and count on substring

I am using SQL Server 2008 R2 and have a table like this:
ID Record
1 IA12345
2 IA33333
3 IA33333
4 IA44444
5 MO12345
I am trying to put together some SQL to return the two rows that contain IA12345 and MO12345. So, I need to match on the partial string of the column "Record". What is complicating my SQL is that I don't want to return matches like IA33333 and IA33333. Clear as mud?
I am getting twisted up in substrings, group by, count and the like!
SELECT ID, Record FROM Table WHERE Record LIKE '%12345'
Select *
from MyTable
where Record like '%12345%'
This will find repeating and/or runs. For example 333 or 123 or 321
Think of it as Rummy 500
Declare #YourTable table (ID int,Record varchar(25))
Insert Into #YourTable values
( 1,'IA12345'),
( 2,'IA33333'),
( 3,'IA33333'),
( 4,'IA44444'),
( 5,'MO12345'),
( 6,'M785256') -- Will be excluded because there is no pattern
Declare #Num table (Num int);Insert Into #Num values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)
Select Distinct A.*
From #YourTable A
Join (
Select Patt=replicate(Num,3) from #Num
Union All
Select Patt=right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3) from #Num where Num<8
Union All
Select Patt=reverse(right('000'+cast((Num*100+Num*10+Num)+12 as varchar(5)),3)) from #Num where Num<8
) B on CharIndex(Patt,Record)>0
Returns
ID Record
1 IA12345
2 IA33333
3 IA33333
4 IA44444
5 MO12345
EDIT
I should add that runs of 3 is too small, it is a small matter tweak the sub-queries so 333 becomes 3333 and 123 becomes 1234

How can I create my numbers matching table populate from zero instead of one?

I'm using a numbers matching table, from one upwards. However, I realize I need to start at zero instead. Can't figure it out..
CREATE TABLE IF NOT EXISTS util_nums (n integer primary key
autoincrement not null);
insert into util_nums(n) select null from (select 0 as n union select 1
union select 2 union select 3 union select 4 union select 5 union select 6
union select 7 union select 8 union select 9 union select 10) a
cross join
(select 0 as n union select 1 union select 2 union select 3 union select 4
union select 5 union select 6 union select 7 union select 8 union select 9
union select 10) b
cross join (select 0 as n union select 1 union select 2
union select 3 union select 4 union select 5 union select 6 union select 7
union select 8 union select 9 union select 10) c;
in sql server it would be easy if you create your table like this
CREATE TABLE util_nums (n as int primary key
identity(0,1) not null,anotherfieldtoholdthenulls integer);
the identity(0,1) means start from zero and increment by 1 ..
update
try using UPDATE SQLITE_SEQUENCE SET seq = -1 WHERE name = 'util_nums' before starting the insert, and see if it is allowed....
You should also be able to do INSERT INTO util_nums VALUES(0)
Sqlite allows you to insert explicit values for the primary key fields:
insert into util_nums(n) values (0);
to Get a lot more rows insert quickly try this after that..
insert into util_nums default values;
insert into util_nums(n) select null from util_nums a, util_nums b, util_nums c, util_nums d;
insert into util_nums(n) select null from util_nums a, util_nums b, util_nums c, util_nums d;
you can temporarly disable auto increment using
SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
But I
suggest update value to 0 after insert
If you're useing SQLite you should probably read this http://www.sqlite.org/autoinc.html . This caught my eye:
If the table has never before
contained any data, then a ROWID of 1
is used.
It doesn't seem to be any way to force autoincrement to start from something other than 1. Also note that it may generate gaps by skipping numbers.
This may work but I have no means of testing at the moment:
Add a row with an ID of -1. Then delete it. It isn't clear from the documentation what happens when you have only negative IDs in the table.
"SQLite Autoincrement"
The important part seems to be...
If no negative ROWID values are inserted explicitly, then automatically
generated ROWID values will always be greater than zero.
So? Create the table, insert a dummy record, with a forced id of -1, and then insert your data. Deleting the dummy record afterwards as/if necessary.
(Inserting a value with -1 will force the next inserted rwo to have an id of 0, assuming the table was otherwise empty.)
SQLite allows you to specify a value here.
Just insert c.n - 1, from your cartesian product, instead of null, and call it a day.

How do you find a missing number in a table field starting from a parameter and incrementing sequentially?

Let's say I have an sql server table:
NumberTaken CompanyName
2 Fred 3 Fred 4 Fred 6 Fred 7 Fred 8 Fred 11 Fred
I need an efficient way to pass in a parameter [StartingNumber] and to count from [StartingNumber] sequentially until I find a number that is missing.
For example notice that 1, 5, 9 and 10 are missing from the table.
If I supplied the parameter [StartingNumber] = 1, it would check to see if 1 exists, if it does it would check to see if 2 exists and so on and so forth so 1 would be returned here.
If [StartNumber] = 6 the function would return 9.
In c# pseudo code it would basically be:
int ctr = [StartingNumber]
while([SELECT NumberTaken FROM tblNumbers Where NumberTaken = ctr] != null)
ctr++;
return ctr;
The problem with that code is that is seems really inefficient if there are thousands of numbers in the table. Also, I can write it in c# code or in a stored procedure whichever is more efficient.
Thanks for the help
Fine, if this question isn't going to be closed, I may as well Copy and paste my answer from the other one:
I called my table Blank, and used the following:
declare #StartOffset int = 2
; With Missing as (
select #StartOffset as N where not exists(select * from Blank where ID = #StartOffset)
), Sequence as (
select #StartOffset as N from Blank where ID = #StartOffset
union all
select b.ID from Blank b inner join Sequence s on b.ID = s.N + 1
)
select COALESCE((select N from Missing),(select MAX(N)+1 from Sequence))
You basically have two cases - either your starting value is missing (so the Missing CTE will contain one row), or it's present, so you count forwards using a recursive CTE (Sequence), and take the max from that and add 1
Tables:
create table Blank (
ID int not null,
Name varchar(20) not null
)
insert into Blank(ID,Name)
select 2 ,'Fred' union all
select 3 ,'Fred' union all
select 4 ,'Fred' union all
select 6 ,'Fred' union all
select 7 ,'Fred' union all
select 8 ,'Fred' union all
select 11 ,'Fred'
go
I would create a temp table containing all numbers from StartingNumber to EndNumber and LEFT JOIN to it to receive the list of rows not contained in the temp table.
If NumberTaken is indexed you could do it with a join on the same table:
select T.NumberTaken -1 as MISSING_NUMBER
from myTable T
left outer join myTable T1
on T.NumberTaken= T1.NumberTaken+1
where T1.NumberTaken is null and t.NumberTaken >= STARTING_NUMBER
order by T.NumberTaken
EDIT
Edited to get 1 too
1> select 1+ID as ID from #b as b
where not exists (select 1 from #b where ID = 1+b.ID)
2> go
ID
-----------
5
9
12
Take max(1+ID) and/or add your starting value to the where clause, depending on what you actually want.

disaggregate summarised table in SQL Server 2008

I've received data from an external source, which is in a summarised format. I need a way to disaggregate this to fit into a system I am using.
To illustrate, suppose the data I received looks like this:
receivedTable:
Age Gender Count
40 M 3
41 M 2
I want this is a disaggregated format like this:
systemTable:
ID Age Gender
1 40 M
2 40 M
3 40 M
4 41 M
5 41 M
Thanks
Karl
Depending of the range of your count you could use a lookup table that holds exactly x records for each integer x. Like this:
create table counter(num int)
insert into counter select 1
insert into counter select 2
insert into counter select 2
insert into counter select 3
insert into counter select 3
insert into counter select 3
insert into counter select 4
insert into counter select 4
insert into counter select 4
insert into counter select 4
then join with this table:
create table source(age int, gender char(1), num int)
insert into source select 40, 'm', 3
insert into source select 30, 'f', 2
insert into source select 20, 'm', 1
--insert into destination(age, gender)
select age, gender
from source
inner join counter on counter.num = source.num
From the "Works on my machine (TM)" stable a recursive query, with all the usual caveats about maximum recursion depth.
with Expanded(exAge, exGender, exRowIndex) as
(
select
Age as exAge,
Gender as exGender,
1 as exRowIndex
from
tblTest1
union all
select
exAge,
exGender,
exRowIndex+1
from
tblTest1 t1
inner join
Expanded e on (e.exAge = t1.Age and e.exGender = t1.Gender and e.exRowIndex < t1.Count)
)
select
exAge,
exGender,
exRowIndex
from
Expanded
order by
exAge,
exGender,
exRowIndex
option (MAXRECURSION 0) -- BE CAREFUL!!
You don't get the row identifier - but inserting the result of the query into a table with an identity column would deal with that.