How to select and join on a query with a table - sql

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

Related

combining insert statements

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

Replace string where ++ exists SQL

This relates to my previous question
What I now want to do is in my value column, if there are any instance of ++ replace this with 999.
So for e.g. if i have 1+2++3this should be updated to 1+2+999+3
How do i achieve this?
Thanks
Oracle Setup:
CREATE TABLE your_table ( value ) AS
SELECT NULL FROM DUAL UNION ALL
SELECT '1' FROM DUAL UNION ALL
SELECT '1+2' FROM DUAL UNION ALL
SELECT '1++2' FROM DUAL UNION ALL
SELECT '+1' FROM DUAL UNION ALL
SELECT '1+' FROM DUAL UNION ALL
SELECT '1+2++3' FROM DUAL;
Query:
SELECT TRIM( BOTH '+' FROM REPLACE( '+' || value || '+', '++', '+999+' ) )
FROM your_table
Output:
VALUE
---------
999
1
1+2
1+999+2
999+1
1+999
1+2+999+3
If you can have more than one missing element to replace in a row then you need a more complicated solution:
Oracle Setup:
CREATE TABLE your_table ( value ) AS
SELECT NULL FROM DUAL UNION ALL
SELECT '1' FROM DUAL UNION ALL
SELECT '1+2' FROM DUAL UNION ALL
SELECT '1++2' FROM DUAL UNION ALL
SELECT '+1' FROM DUAL UNION ALL
SELECT '1+' FROM DUAL UNION ALL
SELECT '1+2++3' FROM DUAL UNION ALL
SELECT '1+2+++3' FROM DUAL UNION ALL
SELECT '+' FROM DUAL;
Query:
SELECT ( SELECT LISTAGG(
COALESCE(
REGEXP_SUBSTR( t.value, '(.*?)(\+|$)', 1, LEVEL, NULL, 1 ),
'999'
),
'+'
) WITHIN GROUP ( ORDER BY LEVEL )
FROM DUAL
CONNECT BY LEVEL <= REGEXP_COUNT( t.value, '\+' ) + 1
) AS value
FROM your_table t
Output:
VALUE
-------------
999
1
1+2
1+999+2
999+1
1+999
1+2+999+3
1+2+999+999+3
999+999

Get Var() and AVG() from many columns

I'm building a query to show average and variance from many columns.
To get the average I use this:
SELECT *,
(SELECT AVG(t.c)
FROM (
SELECT peca_1 UNION ALL
SELECT peca_2 UNION ALL
SELECT peca_3 UNION ALL
SELECT peca_4 UNION ALL
SELECT peca_5 UNION ALL
SELECT peca_6 UNION ALL
SELECT peca_7 UNION ALL
SELECT peca_8 UNION ALL
SELECT peca_9 UNION ALL
SELECT peca_10
) t(c)
) as [media]
from Durabilidade
where cd_durabilidade = 1
The result is:
Now I need a new column with VAR(media) comparing each row with first row.
Any idea?
I think this is a case where cross apply is appropriate. I am assuming that you want the variance of the values as calculated by the var() function:
SELECT *, t.avgval as [media], t.varval
from Durabilidade d cross apply
(select avg(t.val) as avgval, var(t.val) as varval
from (select d.peca_1 union all
select d.peca_2 union all
select d.peca_3 union all
select d.peca_4 union all
select d.peca_5 union all
select d.peca_6 union all
select d.peca_7 union all
select d.peca_8 union all
select d.peca_9 union all
select d.peca_10
) t(val) -- t(val) to work
) t
where cd_durabilidade = 1
Something like this?
SELECT *,
VAR(media) AS [variance]
FROM
(
SELECT *,
(SELECT AVG(t.c)
FROM (
SELECT peca_1 UNION ALL
SELECT peca_2 UNION ALL
SELECT peca_3 UNION ALL
SELECT peca_4 UNION ALL
SELECT peca_5 UNION ALL
SELECT peca_6 UNION ALL
SELECT peca_7 UNION ALL
SELECT peca_8 UNION ALL
SELECT peca_9 UNION ALL
SELECT peca_10
) t(c)
) as [media]
from Durabilidade
where cd_durabilidade = 1
) x
GROUP BY
column1_from_durabilidade
,column2_from_durabilidade
--etc
,media

How to get query to return rows where first three characters of one row match another row?

Here's my data:
with first_three as
(
select 'AAAA' as code from dual union all
select 'BBBA' as code from dual union all
select 'BBBB' as code from dual union all
select 'BBBC' as code from dual union all
select 'CCCC' as code from dual union all
select 'CCCD' as code from dual union all
select 'FFFF' as code from dual union all
select 'GFFF' as code from dual )
select substr(code,1,3) as r1
from first_three
group by substr(code,1,3)
having count(*) >1
This query returns the characters that meet the cirteria. Now, how do I select from this to get desired results? Or, is there another way?
Desired Results
BBBA
BBBB
BBBC
CCCC
CCCD
WITH code_frequency AS (
SELECT code,
COUNT(1) OVER ( PARTITION BY SUBSTR( code, 1, 3 ) ) AS frequency
FROM table_name
)
SELECT code
FROM code_frequency
WHERE frequency > 1
WITH first_three AS (
...
)
SELECT *
FROM first_three f1
WHERE EXISTS (
SELECT 1 FROM first_three f2
WHERE f1.code != f2.code
AND substr(f1.code, 1, 3) = substr(f2.code, 1, 3)
)
select res from (select res,count(*) over
(partition by substr(res,1,3) order by null) cn from table_name) where cn>1;

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