insert random strings from a list using sql - sql

i've created a table like this : region(id, name) and i want to insert into this table some rows , the name should be choosed randomly from a list like ['east', 'west'], how can i do that ?

Insert 10 random rows with...
Oracle:
INSERT INTO region(name)
SELECT rndm.name
FROM (SELECT 1 n
FROM dual
CONNECT BY LEVEL <= 365
) gen
CROSS
JOIN (SELECT 'west' name FROM dual
UNION ALL
SELECT 'east' FROM dual
UNION ALL
SELECT 'north' FROM dual
) rndm
WHERE rownum <= 10
ORDER BY DBMS_RANDOM.VALUE
SQL Server:
INSERT INTO region (name)
SELECT TOP 10 rndm.name
FROM sys.all_objects a1
CROSS
JOIN (VALUES ('east'),
('west')) rndm(name)
ORDER BY CHECKSUM(NEWID())
MySQL:
INSERT INTO region (name)
SELECT rndm.name
FROM information_schema.columns v
CROSS
JOIN (SELECT 'east' as name UNION ALL
SELECT 'west') rndm
ORDER BY RAND()
LIMIT 10
Postgres:
INSERT INTO region(NAME)
SELECT unnest(ARRAY['west','east'])
FROM generate_series(1, 100)
ORDER BY random()
LIMIT 10

This is an Oracle solution. The first subquery generates ten random integers between 1 and 3, using Oracle's CONNECT BY syntax. The second subquery associates the region name with a number between 1 and 3. These are joined in the main query to populate the table:
insert into region (id, name)
with rnd as (
select level as lvl, round(DBMS_RANDOM.VALUE(0.5,3.4999999999), 0) as rnd
from dual
connect by level <= 10
) , regn as (
select 1 as rno, 'west' as rname from dual union all
select 2 as rno, 'east' as rname from dual union all
select 3 as rno, 'north' as rname from dual
)
select rnd.lvl
, regn.rname
from rnd
join regn on rnd.rnd = regn.rno
/

Related

How to select a record which have all id's in SQL?

I want select record which have all id's.
Example:
Name
ID
Ram
3
Ajay
1
Mogan
3
Ram
1
Ram
2
Here Ram have all id's (1,2,3). So, I want result as Ram.
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 UNION ALL
SELECT'AJAY',3 UNION ALL
SELECT 'MOGAN',2 UNION ALL
SELECT 'KUMAR',3 UNION ALL
SELECT 'RAM',2 UNION ALL
SELECT 'JAYA',1 UNION ALL
SELECT 'KABIL',3 UNION ALL
SELECT 'RAM',3
)
SELECT C.NAME
FROM CTE AS C
GROUP BY C.NAME
HAVING COUNT(DISTINCT C.CODE)=(SELECT COUNT(DISTINCT CODE) FROM CTE )
As far as I know, this is called "relational division". You can try my query or look for another possible solution
Select * from table where upper(name) = 'RAM'
This query would bring back all the IDs for RAM alone
how about string agg.
CREATE TABLE MyTable (
ID int,
Name varchar(255),
);
Insert into MyTable(ID, Name) values (1, 'Ram');
Insert into MyTable(ID, Name) values (2, 'Ram');
Insert into MyTable(ID, Name) values (3, 'Ram');
Insert into MyTable(ID, Name) values (1, 'Ajay');
Insert into MyTable(ID, Name) values (1, 'Mogan');
select Name, string_agg(ID, ',') as Ids
from MyTable
group by Name;
result
Ajay 1
Mogan 1
Ram 1,2,3
see result here
http://sqlfiddle.com/#!18/923bf/4
With reference to the with clause used by #surgey above,
WITH CTE(NAME,CODE)AS
(
SELECT 'RAM',1 from dual UNION ALL
SELECT'AJAY',3 from dual UNION ALL
SELECT 'MOGAN',2 from dual UNION ALL
SELECT 'KUMAR',3 from dual UNION ALL
SELECT 'RAM',2 from dual UNION ALL
SELECT 'JAYA',1 from dual UNION ALL
SELECT 'KABIL',3 from dual UNION ALL
SELECT 'RAM',3 from dual
)
select name, code, rank() over(partition by name order by code) rank
from cte
this query, it will bring back everybody in the and group them by name. THis could be one possible solution other use tou can use an "IN" clause in your where as shown below
Select * from table where upper(name) in ('RAM','AJAY')
If are you using MySql this will solve your issue:
SELECT r1.name
FROM raws r1
LEFT JOIN raws r2 ON r1.id = r2.id AND r1.name = r2.name
WHERE r2.id IN (1, 2, 3)
GROUP by r1.name
HAVING count(r2.id) = 3; # count of numbers in IN (1, 2, 3)
And if you have identifier in your table use it for join instead
of r1.id = r2.id AND r1.name = r2.name

Random records for a row

I have the following table strvals() with data. I'm looking to randomly choose 2 rows from strval() table and populate table S1 in a loop.
I want something like this
Create table s1(id primary key,strval1, strval2) as
select level,random_rec(strvals), random_rec(strvals)
from dual
connect by level<=10;
The caveat is the column strval1 has to be different THEN strval2 for each row.
Valid output
1, 'AAAA', 'BBBB'
2, 'CCCC', 'BBBB'
3, 'CCCC', 'AAAA'
Not valid
1, 'AAAA', 'AAAA'
Create table strvals(
strval varchar2(4),
constraint pk_strval primary key (strval)
);
insert into strvals
values(
'AAAA'
);
insert into strvals
values(
'BBBB'
);
insert into strvals
values(
'CCCC'
);
Getting a random string from a table can be tricky. One method is to use correlated subqueries -- the correlation clause ensures that the subquery is not "optimized" to run only once.
So, here is one method:
select id, strval,
(select s2.strval
from strvals s2
where s2.strval <> x.strval and x.id > 0
order by dbms_random.random fetch first 1 row only
) as strval2
from (select id,
(select strval
from strvals
where x.id > 0
order by dbms_random.random fetch first 1 row only
) as strval
from (select level as id
from dual
connect by level < 25
) x
) x;
And here is a db<>fiddle.
To reduce a number of slow dbms_random.value in case of many rows, I would suggest to use this technique:
with
rand as (select row_number()over(order by dbms_random.value()) n,strval from strvals)
,cnt as (select count(*) m from rand)
,generator as (select level id, ceil(dbms_random.value()*cnt.m) rnd from cnt connect by level<=10)
select generator.id, rand.strval
from generator
join rand on rand.n=generator.rnd;
As you can see, I sort the table strvals once by dbms_random.value (rand view), so each row has own random integer number, then I count them to get maximum N. And then I calculate random N for each generated row so we can join rand view using hash join.
Update: for 2 strvals: DBFiddle
with
rand as (select row_number()over(order by dbms_random.value()) n,strval from strvals)
,cnt as (select count(*) m from rand)
,generator as (
select
level id,
ceil(dbms_random.value()*cnt.m) rnd1,
ceil(dbms_random.value()*cnt.m) rnd2
from cnt connect by level<=10
)
select
generator.id,
rnd1.strval,
rnd2.strval
from generator
join rand rnd1 on rnd1.n=generator.rnd1
join rand rnd2 on rnd2.n=generator.rnd2;
Update2: now with 2 strvals: DBFiddle
with
rand as (
select
row_number()over(order by dbms_random.value()) n
,s1.strval strval1
,s2.strval strval2
from strvals s1
join strvals s2
on s1.strval!=s2.strval
)
,cnt as (select count(*) m from rand)
,generator as (
select
level id,
ceil(dbms_random.value()*cnt.m) rnd
from cnt connect by level<=10
)
select
generator.id,
rand.strval1,
rand.strval2
from generator
join rand on rand.n=generator.rnd
order by 1
;

Oracle SQL Replace multiple characters in different positions

I'm using Oracle 11g and I'm having trouble replacing multiple characters based on positions mentioned in a different table. For example:
Table 1
PRSKEY POSITION CHARACTER
123 3 ć
123 9 ć
Table 2
PRSKEY NAME
123 Becirovic
I have to replace the NAME in Table 2 to Bećirović.
I've tried regexp_replace but this function doesn't provide replacing more then 1 position, is there an easy way to fix this?
Here's another way to do it.
with tab1 as (select 123 as prskey, 3 as position, 'ć' as character from dual
union select 123, 9, 'ć' from dual),
tab2 as (select 123 as prskey, 'Becirovic' as name from dual)
select listagg(nvl(tab1.character, namechar)) within group(order by lvl)
from
(select prskey, substr(name, level, 1) as namechar, level as lvl
from tab2
connect by level <= length(name)
) splitname
left join tab1 on position = lvl and tab1.prskey = splitname.prskey
;
Simple solution using cursor ...
create table t1 (
prskey int,
pos int,
character char(1)
);
create table t2
(
prskey int,
name varchar2(100)
);
insert into t1 values (1, 1, 'b');
insert into t1 values (1, 3, 'e');
insert into t2 values (1, 'dear');
begin
for t1rec in (select * from t1) loop
update t2
set name = substr(name, 1, t1rec.pos - 1) || t1rec.character || substr(name, t1rec.pos + 1, length(name) - t1rec.pos)
where t2.prskey = t1rec.prskey;
end loop;
end;
/
I would prefer approach via PL/SQL, but in your tag only 'sql', so I made this monster:
with t as (
select 123 as id, 3 as pos, 'q' as new_char from dual
union all
select 123 as id, 6 as pos, 'z' as new_char from dual
union all
select 123 as id, 9 as pos, '1' as new_char from dual
union all
select 456 as id, 1 as pos, 'A' as new_char from dual
union all
select 456 as id, 4 as pos, 'Z' as new_char from dual
),
t1 as (
select 123 as id, 'Becirovic' as str from dual
union all
select 456 as id, 'Test' as str from dual
)
select listagg(out_text) within group (order by pos)
from(
select id, pos, new_char, str, prev, substr(str,prev,pos-prev)||new_char as out_text
from(
select id, pos, new_char, str, nvl(lag(pos) over (partition by id order by pos)+1,1) as prev
from (
select t.id, pos, new_char, str
from t, t1
where t.id = t1.id
) q
) a
) w
group by id
Result:
Beqirzvi1
AesZ

Which value(s) in WHERE CLAUSE LIST are not available in the table

I want to search which value(s) in MY WHERE CLAUSE LIST are not available in the table.
Table name is test
Column1
--------------
1
2
3
My query : I have a search list 2, 3, 4, 5 and I want to see which all are not in my database. When I query, I should get 4, 5 and NOT 1.
I do not want the list of values which are there in the table and not in where clause list(select * from test where column1 not in (2, 3, 4, 5)
Can someone please help ?
WITH my_list AS
(SELECT regexp_substr('2,3,4,5', '[^,]+', 1, LEVEL) AS search_val
FROM dual
CONNECT BY level <= regexp_count('2,3,4,5',',') + 1
)
SELECT *
FROM my_list
WHERE NOT EXISTS
(SELECT 'X' FROM YOUR_TABLE WHERE YOUR_COLUMN = search_val
);
Let's Convert the comma separated values into a view and then do what's needed.
You can do it as follows:
SELECT List FROM
(SELECT 2 as List
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5) T
WHERE List NOT IN
(SELECT Column1 FROM TableName)
In this case, I would do a simple select
select *
from test
where column1 in (2, 3, 4, 5)
and do the set operation in the host language (Java, C++, Perl, ...).
This seems far simpler than any SQL solution.
with cte as
(select 2 as val from dual
union all
select 3 from dual
union all
select 4 from dual
union all
select 5 from dual
union all
)
select * from cte as t1
where not exists
( select * from test as t2 where t1.val = t2.column1)
For a large number of values you might better create a temporary table, insert the rows and then use this instead of the common table expression.
Try below Query:
WITH MY_DATA_TABLE AS
(
SELECT regexp_substr('2,3,4,5', '[^,]+', 1, LEVEL) AS MY_DATA_VALUE
FROM dual
CONNECT BY level <= (length('2,3,4,5') - length(replace('2,3,4,5', ',')))
)
SELECT *
FROM MY_DATA_TABLE
WHERE NOT EXISTS
(SELECT 'TRUE' FROM TABLE_NAME WHERE TABLE_FIELD_VALUE = MY_DATA_VALUE
);
Your query with huge data would translate in ORACLE to:
WITH MY_DATA_TABLE AS
(
SELECT regexp_substr('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802', '[^,]+', 1, LEVEL) AS MY_DATA_VALUE
FROM dual
CONNECT BY level <= (length('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802') - length(replace('1,4,5,8,9,12,13,14,20,39,43,48,51,54,55,57,61,65,68,75,78,80,81,82,91,92,96,99,‌​102,103,109,112,113,224,227,249,250,251,600,601,604,605,608,609,614,802', ',')))
)
SELECT *
FROM MY_DATA_TABLE
WHERE NOT EXISTS
(SELECT 'TRUE' FROM TABLE_NAME WHERE TABLE_FIELD_VALUE = MY_DATA_VALUE
);

split string into several rows

I have a table with a string which contains several delimited values, e.g. a;b;c.
I need to split this string and use its values in a query. For example I have following table:
str
a;b;c
b;c;d
a;c;d
I need to group by a single value from str column to get following result:
str count(*)
a 1
b 2
c 3
d 2
Is it possible to implement using single select query? I can not create temporary tables to extract values there and query against that temporary table.
From your comment to #PrzemyslawKruglej answer
Main problem is with internal query with connect by, it generates astonishing amount of rows
The amount of rows generated can be reduced with the following approach:
/* test table populated with sample data from your question */
SQL> create table t1(str) as(
2 select 'a;b;c' from dual union all
3 select 'b;c;d' from dual union all
4 select 'a;c;d' from dual
5 );
Table created
-- number of rows generated will solely depend on the most longest
-- string.
-- If (say) the longest string contains 3 words (wont count separator `;`)
-- and we have 100 rows in our table, then we will end up with 300 rows
-- for further processing , no more.
with occurrence(ocr) as(
select level
from ( select max(regexp_count(str, '[^;]+')) as mx_t
from t1 ) t
connect by level <= mx_t
)
select count(regexp_substr(t1.str, '[^;]+', 1, o.ocr)) as generated_for_3_rows
from t1
cross join occurrence o;
Result: For three rows where the longest one is made up of three words, we will generate 9 rows:
GENERATED_FOR_3_ROWS
--------------------
9
Final query:
with occurrence(ocr) as(
select level
from ( select max(regexp_count(str, '[^;]+')) as mx_t
from t1 ) t
connect by level <= mx_t
)
select res
, count(res) as cnt
from (select regexp_substr(t1.str, '[^;]+', 1, o.ocr) as res
from t1
cross join occurrence o)
where res is not null
group by res
order by res;
Result:
RES CNT
----- ----------
a 2
b 2
c 3
d 2
SQLFIddle Demo
Find out more about regexp_count()(11g and up) and regexp_substr() regular expression functions.
Note: Regular expression functions relatively expensive to compute, and when it comes to processing a very large amount of data, it might be worth considering to switch to a plain PL/SQL. Here is an example.
This is ugly, but seems to work. The problem with the CONNECT BY splitting is that it returns duplicate rows. I managed to get rid of them, but you'll have to test it:
WITH
data AS (
SELECT 'a;b;c' AS val FROM dual
UNION ALL SELECT 'b;c;d' AS val FROM dual
UNION ALL SELECT 'a;c;d' AS val FROM dual
)
SELECT token, COUNT(1)
FROM (
SELECT DISTINCT token, lvl, val, p_val
FROM (
SELECT
regexp_substr(val, '[^;]+', 1, level) AS token,
level AS lvl,
val,
NVL(prior val, val) p_val
FROM data
CONNECT BY regexp_substr(val, '[^;]+', 1, level) IS NOT NULL
)
WHERE val = p_val
)
GROUP BY token;
TOKEN COUNT(1)
-------------------- ----------
d 2
b 2
a 2
c 3
SELECT NAME,COUNT(NAME) FROM ( SELECT NAME FROM ( (SELECT rownum as ID, REGEXP_SUBSTR('a;b;c', '[^;]+', 1, LEVEL ) NAME
FROM dual CONNECT BY REGEXP_SUBSTR('a;b;c', '[^;]+', 1, LEVEL) IS NOT NULL))
UNION ALL (SELECT NAME FROM ( (SELECT rownum as ID, REGEXP_SUBSTR('b;c;d', '[^;]+', 1, LEVEL ) NAME
FROM dual CONNECT BY REGEXP_SUBSTR('b;c;d', '[^;]+', 1, LEVEL) IS NOT NULL)))
UNION ALL
(SELECT NAME FROM ( (SELECT rownum as ID, REGEXP_SUBSTR('a;c;d', '[^;]+', 1, LEVEL ) NAME
FROM dual CONNECT BY REGEXP_SUBSTR('a;c;d', '[^;]+', 1, LEVEL) IS NOT NULL)))) GROUP BY NAME
NAME COUNT(NAME)
----- -----------
d 2
a 2
b 2
c 3