combining insert statements - sql

How would I multiple insert statements together? There's 8 different descriptions that I want to insert. For example:
insert into table (
p_number, description, period
)
select p.p_number, g.description, g.period,
from other_table p
,('desc1' as description
,2015 + Level as period
from dual connect by 2015 + Level <=2050) g
where p.flag = 'Y';
insert into table (
p_number, description, period
)
select p.p_number, g.description, g.period,
from other_table p
,('desc2' as description
,2015 + Level as period
from dual connect by 2015 + Level <=2050) g
where p.flag = 'Y';

you can use union all
insert into table (
p_number, description, period
)
select p.p_number, g.description, g.period,
from other_table p
,('desc1' as description
,2015 + Level as period
from dual connect by 2015 + Level <=2050) g
where p.flag = 'Y'
union all
select p.p_number, g.description, g.period,
from other_table p
,('desc2' as description
,2015 + Level as period
from dual connect by 2015 + Level <=2050) g
where p.flag = 'Y';

You could use CTEs to generate the descriptions and periods, and cross join those to the real source table:
insert into target_table (
p_number, description, period
)
with descriptions (description) as (
select 'desc1' from dual
union all select 'desc2' from dual
-- etc.
),
periods (period) as (
select 2015 + level
from dual
connect by level <= 35
)
select s.p_number, d.description, p.period,
from source_table s
cross join descriptions d
cross join periods p
where s.flag = 'Y';
Untested, of course...

Use cross joins (and unions):
insert into table (
p_number, description, period
)
select p.p_number, d.description, g.period
from other_table p cross join (
select 'desc1' description from dual union
select 'desc2' from dual union
...
select 'desc1' from dual
) d cross join (
select 2015 + Level as period
from dual connect by 2015 + Level <=2050
) g

Related

insert random strings from a list using 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
/

Combine two table in Oracle Sql

I have two tables.
One is
ID REFPARTS
-- --------
100 '1,2'
101 '1'
Second table
PART_ID AMOUNT
------ --------
1 50
2 25
Final Table
ID REFPARTS AMOUNT
-- -------- -------
100 '1,2' 75
101 '1' 50
How can I get final table?
Thanks in advance.
This is a horrible data model. You should not be storing lists of numeric ids in a comma delimited string. SQL has a wonderful way to represent lists. It is called a "table", not a "string".
In your case, you could do:
select t1.id, sum(t2.amount)
from table1 t1 join
table2 t2
on replace(t1.refparts, ',', ''',''') like '%''' || t2.partid || '''%'
group by t1.id;
Even though you can do this using string manipulation, you should put your efforts into fixing the data model.
I am splitting the comma seperated string to rows in my with clause "data" this is followed by a join with the second table and grouping by the id values.
create table t(id int, refparts varchar2(100))
insert into t values(100,'1,2');
insert into t values(101,'1');
create table t2(part_id int, amount int);
insert into t2 values(1,50);
insert into t2 values(2,25);
with data
as (
select a.id
,rtrim(
substr(a.refparts|| ','
,instr(','||a.refparts||',',',',1,lvl)
,instr(','||a.refparts||',',',',1,lvl+1) - instr(','||a.refparts||',',',',1,lvl)
)
,',') as col2
from t a
join (select level as lvl
from dual
connect by level<=10) b
on b.lvl <=length(a.refparts) - length(replace(a.refparts,',','')) + 1
)
select a.id
,sum(b.amount) as summed_val
from data a
join t2 b
on a.col2=b.part_id
group by a.id
WITH tab1 AS (
SELECT 100 AS id_, '1,2' AS refparts FROM dual
UNION ALL
SELECT 101 AS id_, '1' AS refparts FROM dual
),
tab2 AS (
SELECT 1 AS part_id , 50 AS amount FROM dual
UNION ALL
SELECT 2 AS part_id , 25 AS amount FROM dual
)
SELECT t1.id_, t1.refparts, SUM(t2.amount)
FROM (
SELECT DISTINCT id_, trim(regexp_substr(refparts, '[^,]+', 1, LEVEL)) refparts
FROM tab1
CONNECT BY instr(refparts, ',', 1, LEVEL - 1) > 0
) t1Splited
INNER JOIN tab1 t1 ON t1.id_ = t1Splited.id_
INNER JOIN tab2 t2 ON t2.part_id = t1Splited.refparts
GROUP BY t1.id_, t1.refparts
ORDER BY t1.id_
;

Join two subqueries with ON or USING

I have two queries I need to LEFT JOIN the first one with the second one. The purpose is to wrap all of this inside of something else bigger. I got both the first and second queries working alone but cannot get them to join.
First Query:
SELECT *
FROM (
SELECT Source as system, DT as ts, Status as statusCode
FROM (
(SELECT 'SOURCE1' Source FROM Dual
UNION SELECT 'SOURCE2' FROM Dual
UNION SELECT 'SOURCE3' FROM Dual
UNION SELECT 'SOURCE4' FROM Dual
) system
CROSS JOIN (
SELECT
TO_DATE('09-30-2013','MM-DD-YYYY') - 1 + LEVEL dt
FROM dual
CONNECT BY
LEVEL <= ( TO_DATE('10/05/2013','MM/DD/YYYY')
- TO_DATE('09/30/2013','MM/DD/YYYY')) + 1
) ts
CROSS JOIN (
SELECT 'O' Status FROM Dual
UNION SELECT 'C' FROM Dual
) statusCode
)--For some reason cannot name this so need to wrap in another select *
)Duals
Second Query: (there would be a LEFT JOIN) between here
LEFT JOIN
Was tried
Select * FROM(
SELECT myTable1.system, TO_CHAR(maxResults.ts,'YYYY-MM-DD') as ts, myTable1.statusCode
FROM (
SELECT table_id, MAX(ts) as ts
FROM myTable1_history
WHERE ts BETWEEN TO_TIMESTAMP('2013-09-29','yyyy-mm-dd') AND TO_TIMESTAMP('2013-10-06','yyyy-mm-dd')
GROUP BY table_id )maxResults
JOIN myTable1
ON maxResults.table_id = myTable1.table_id
WHERE myTable1.statusCode = 'C'
UNION ALL
SELECT myTable1.system as "system", TO_CHAR(myTable1.ts,'YYYY-MM-DD') as "ts", 'O' as "statusCode"
FROM myTable1
WHERE myTable1.ts BETWEEN TO_TIMESTAMP('2013-09-29','yyyy-mm-dd') AND TO_TIMESTAMP('2013-10-06','yyyy-mm-dd')
--AND myTable1.statusCode = 'O'
)Records
and
USING (system, ts, statusCode)
I tried just sticking in a LEFT JOIN in the middle of the two queries but didn't work (I am probably doing it wrong) as shown
EDIT: Added the JOIN and USING as example of what was not working, receiving "invalid table name"
This is a guess, assuming you want to join on all columns?
(SELECT * FROM (
SELECT system, ts, statuscode
FROM (SELECT Source as system, DT as ts, Status as statusCode
FROM ((SELECT 'SOURCE1' Source FROM Dual
UNION SELECT 'SOURCE2' FROM Dual
UNION SELECT 'SOURCE3' FROM Dual
UNION SELECT 'SOURCE4' FROM Dual
) system CROSS JOIN (SELECT TO_DATE('09-30-2013','MM-DD-YYYY') - 1 + LEVEL dt
FROM dual
CONNECT BY
LEVEL <= ( TO_DATE('10/05/2013','MM/DD/YYYY')
- TO_DATE('09/30/2013','MM/DD/YYYY')) + 1
) ts CROSS JOIN (SELECT 'O' Status FROM Dual
UNION SELECT 'C' FROM Dual) statusCode
)
))duals LEFT JOIN
(Select * FROM(
SELECT myTable1.system, TO_CHAR(maxResults.ts,'YYYY-MM-DD') as ts, myTable1.statusCode
FROM (
SELECT table_id, MAX(ts) as ts
FROM myTable1_history
WHERE ts BETWEEN TO_TIMESTAMP('2013-09-29','yyyy-mm-dd') AND TO_TIMESTAMP('2013-10-06','yyyy-mm-dd')
GROUP BY table_id )maxResults
JOIN myTable1
ON maxResults.table_id = myTable1.table_id
WHERE myTable1.statusCode = 'C'
UNION ALL
SELECT myTable1.system, TO_CHAR(myTable1.ts,'YYYY-MM-DD') as ts, 'O' as statusCode
FROM myTable1
WHERE myTable1.ts BETWEEN TO_TIMESTAMP('2013-09-29','yyyy-mm-dd') AND TO_TIMESTAMP('2013-10-06','yyyy-mm-dd')
--AND myTable1.statusCode = 'O'
) Records ON duals.system = records.system AND duals.ts = records.ts AND duals.statusCode = records.statusCode

How to select and join on a query with a table

I think this is just a syntax issue for me on Join but I am trying to Join a query to an existing table
select *
from
(
(select 'Source1' Source from Dual
union select 'Source2' from Dual
union select 'Source3' from Dual
union select 'Source4' from Dual
)
cross join (
select 'O' Status from Dual
union select 'C' from Dual
)
cross join (
SELECT
TO_DATE('09/30/2013','mm/dd/yyyy') - 1 + LEVEL dt
FROM dual
CONNECT BY
LEVEL <= ( TO_DATE('10/05/2013','mm/dd/yyyy')
- TO_DATE('09/30/2013','mm/dd/yyyy')) + 1
)
) as x
left join
(
select myTable.mySource
from myTable
) as y
on y.err_sts_cd = x.Status
You should be able to just remove most of the grouping parens...
select *
from
(select 'Source1' Source from Dual
union select 'Source2' from Dual
union select 'Source3' from Dual
union select 'Source4' from Dual
) s
cross join (
select 'O' Status from Dual
union select 'C' from Dual
) x
cross join (
SELECT
TO_DATE('09/30/2013','mm/dd/yyyy') - 1 + LEVEL dt
FROM dual
CONNECT BY
LEVEL <= ( TO_DATE('10/05/2013','mm/dd/yyyy')
- TO_DATE('09/30/2013','mm/dd/yyyy')) + 1
) d
left join
myTable y
on y.err_sts_cd = x.Status
There is no y.err_sts_cd
left join
(
select myTable.mySource
from myTable
) as y
on y.err_sts_cd = x.Status
You need to either join using y.mySource or actually select err_sts_cd from myTable, aledgedly:
select myTable.mySource, myTable.err_sts_cd
from myTable

TSQL Update statement with Join

I have two tables with a parent/child relationship. I want to update the parent with data from the child. However assuming there are 2 children I would like to be able to pick which child is used for the update depending on some other column from the child.
Here is what I have so far:
Parent: #test
Child: #exdat
Expected outcome, result of parent after update should contain only Capital letters. I want to update the parent with some data from the child, but if more than one exists I'd rather choose a child with a dimp of p1 over p2, p2 over p3 and p3 over p4
DECLARE #test TABLE
(
id int,
val char(1)
);
DECLARE #exdat TABLE
(
id int,
dval char(1),
dimp char(2)
);
INSERT INTO #test (id,val)
SELECT 1,'a'
UNION ALL SELECT 2,'b'
UNION ALL SELECT 3,'c'
UNION ALL SELECT 4,'d'
UNION ALL SELECT 5,'e'
UNION ALL SELECT 6,'f'
UNION ALL SELECT 7,'g'
;
INSERT INTO #exdat (id,dval,dimp)
SELECT 1,'A','p1'
UNION ALL SELECT 2,'B','p3'
UNION ALL SELECT 3,'C','p1'
UNION ALL SELECT 4,'D','p2'
UNION ALL SELECT 5,'E','p2'
UNION ALL SELECT 6,'F','p3'
UNION ALL SELECT 7,'w','p2'
UNION ALL SELECT 7,'g','p3'
UNION ALL SELECT 7,'G','p1'
UNION ALL SELECT 7,'z','p4'
;
UPDATE #test SET
val = e.dval
FROM
#test t
INNER JOIN #exdat e ON t.id = e.id
;
SELECT * FROM #test;
Result:
1 A
2 B
3 C
4 D
5 E
6 F
7 w <-- problem illustrated here
This "w" could have been any of the values w,g,G,z. So I am asking how can I prioritize the child selection based on some other column ?
What you want to do instead of a join is a subquery. Something like this:
UPDATE
a
SET
a.val = ISNULL((
SELECT TOP 1 x.dval
FROM #exdat x
WHERE x.id = a.id
ORDER BY x.magic_field -- <- here's how you specify precedence
), 'ReasonableDefault')
FROM
#test a
Trying using a CROSS APPLY with your update. The example below orders by the #extdat.dimp value:
DECLARE #test TABLE
(
id int,
val char(1)
);
DECLARE #exdat TABLE
(
id int,
dval char(1),
dimp char(2)
);
INSERT INTO #test (id,val)
SELECT 1,'a'
UNION ALL SELECT 2,'b'
UNION ALL SELECT 3,'c'
UNION ALL SELECT 4,'d'
UNION ALL SELECT 5,'e'
UNION ALL SELECT 6,'f'
UNION ALL SELECT 7,'g'
;
INSERT INTO #exdat (id,dval,dimp)
SELECT 1,'A','p1'
UNION ALL SELECT 2,'B','p3'
UNION ALL SELECT 3,'C','p1'
UNION ALL SELECT 4,'D','p2'
UNION ALL SELECT 5,'E','p2'
UNION ALL SELECT 6,'F','p3'
UNION ALL SELECT 7,'w','p2'
UNION ALL SELECT 7,'g','p3'
UNION ALL SELECT 7,'G','p1'
UNION ALL SELECT 7,'z','p4'
;
UPDATE #test
SET
t.val = e.dval
FROM #test as t
CROSS APPLY
(
SELECT TOP(1) * FROM #exdat as cae
WHERE t.id = cae.id
ORDER BY cae.dimp
) as e
;
SELECT * FROM #test;
If you use this method your results would look like this:
Result:
1 A
2 B
3 C
4 D
5 E
6 F
7 G
You can modify this by changing the order by in your CROSS APPLY
UPDATE #test
SET t.val = e.dval
FROM #test t
JOIN #exdat e
ON t.id = e.id
JOIN
( SELECT id
, MIN(dimp) AS dimp --orders by dimp ascending
FROM #exdat
WHERE dval = UPPER(dval) --keeps only rows with capital letters in dval
GROUP BY id
) AS g
ON e.id = g.id
AND e.dimp = g.dimp
I think using the ranking functions can be put to good use here.
In this sample I used DENSE_RANK to pick the highest dimp value by ORDER BY dimp and then looking for the one had the rank of one.
WITH cte
AS (SELECT Dense_rank() OVER (PARTITION BY id ORDER BY dimp) AS foo,
*
FROM #exdat)
UPDATE #test
SET val = e.dval
FROM #test t
INNER JOIN cte e
ON t.id = e.id
WHERE foo = 1;