To split delimited value in column input in where clause - oracle

I need to split a column which is Pipe delimited and compare with records. Something like this
select 1
from T1 t1
where t1.date_col not between '01-JAN-2005' and '31-JAN-2005';
I need to fill the between clause value from reference table where the data is something like
ref_table
col_1
01-JAN-2005 | 31-JAN-2005
Query I am trying to achieve
REGEXP_SUBSTR ( col_1
, '^[^|]+') from ref_table
Which is resulting into 01-JAN-2005.
Table T1
date_col
01-Jan-05
15-Jan-05
31-Mar-05
Ref_table
col_1
01-JAN-2005 | 31-JAN-2005

You can do as this:
--Sample data
with t1 as (
select '01-Jan-05' col_1 union
select '15-Jan-05' union
select '31-Mar-05'
),
Ref_table as (
select '01-JAN-2005 | 31-JAN-2005' col_1
)
select *
from t1,
Ref_table r
where to_date(t1.col_1, 'DD/MON/YY')
not between to_date(trim(regexp_replace(r.col_1, '(.*)\|.*', '\1')), 'DD/MON/YY')
and to_date(trim(regexp_replace(r.col_1, '.*\|(.*)', '\1')), 'DD/MON/YY')
Although you really should improve your ref_table design. Store values with some char separated always turns out to be a problem.

Join the dates from table t1 with the intervals from the reference table and subtract the result from the original set of dates:
select t11.date_col
from t1 t11
minus
select t12.date_col
from t1 t12
join (
select to_date ( trim ( substr(col_1, 1, instr(col_1, '|') - 1) ), 'DD-Mon-YYYY' ) d_from
, to_date ( trim ( substr(col_1, instr(col_1, '|') + 1) ), 'DD-Mon-YYYY' ) d_to
from ref_table
) rt on (
rt.d_from <= t12.date_col
AND rt.d_to >= t12.date_col
)
;
I assume that col_1 from your reference table contains the excluded intervals in pairs.

Related

Oracle adding a subquery in a CTE

I have the following setup, which works fine and generates output as expected.
I'm trying to add the locations subquery into the CTE so my output will have a random location_id for each row.
The subquery is straight forward and should work but I am getting syntax errors when I try to place it into the 'data's CTE. I was hoping someone could help me out.
CREATE TABLE employees(
employee_id NUMBER(6),
emp_name VARCHAR2(30)
);
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(1, 'John Doe');
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(2, 'Jane Smith');
INSERT INTO employees(
employee_id,
emp_name
) VALUES
(3, 'Mike Jones');
CREATE TABLE locations AS
SELECT level AS location_id,
'Door ' || level AS location_name
FROM dual
CONNECT BY level <=
with rws as (
select level rn from dual connect by level <= 5 ),
data as ( select e.*,round (dbms_random.value(1,5)
) n from employees e)
select employee_id,
emp_name,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws
join data d on rn <= n
order by employee_id;
-- trying to make this work
with rws as ( select level rn from dual connect by level <= 5 ),
data as ( select e.*, loc.location_id = (
select location_id
from locations order by dbms_random.value()
fetch first 1 row only
),
round (dbms_random.value(1,5)
) n from employees e )
select employee_id,
emp_name,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws
join data d on rn <= n
order by employee_id;
You need to alias the subquery column expression, rather than trying to assign it to a [variable] name. So instead of this:
with rws as ( select level rn from dual connect by level <= 5 ),
data as ( select e.*, loc.location_id = (
select location_id
from locations order by dbms_random.value()
fetch first 1 row only
),
round (dbms_random.value(1,5)
) n from employees e )
you would do this:
with rws as (
select level rn
from dual
connect by level <= 5
),
data as (
select e.*,
(
select location_id
from locations
order by dbms_random.value()
fetch first 1 row only
) as location_id,
round (dbms_random.value(1,5)) as n
from employees e
)
db<>fiddle
But yes, you'll get the same location_id for each row, which probably isn't what you want.
There are probably better ways to avoid it (or to approach whatever you're actually trying to achieve) but one option is to force the subquery to be correlated by adding something like:
where location_id != -1 * e.employee_id
db<>fiddle
although that might be expensive. It's probably worth asking a new question about that specific aspect.
I am getting the same location_id for every employee_id, which I don't want either.
The subquery is in the wrong place then; move it to the main query, and correlate against both ID and n:
with rws as (
select level rn
from dual
connect by level <= 5
),
data as (
select e.*,
round (dbms_random.value(1,5)) as n
from employees e
)
select d.employee_id,
d.emp_name,
(
select location_id
from locations
where location_id != -1 * d.employee_id * d.n
order by dbms_random.value()
fetch first 1 row only
) as location_id,
trunc (sysdate) + dbms_random.value (0, 5) AS random_date
from rws r
join data d on r.rn <= d.n
order by d.employee_id;
db<>fiddle
Or move the location part to a new CTE, I suppose, with its own row number; and join that on one of your other generated values.

Error when inserting CTE table values into physical table

I have a complex query that creates a master CTE_Table form other CTE_Tables. I want to insert the results of the master CTE_Table into a physical table. I'm using Teradata version 15.10.04.03
SELECT Failed. [3707] Syntax error, expected something like a 'SELECT' keyword or '(' or a 'TRANSACTIONTIME' keyword or a 'VALIDTIME' keyword between ')' and the 'INSERT' keyword.
DROP TABLE dbname.physicalTablename ;
CREATE MULTISET TABLE dbname.physicalTablename ,
NO FALLBACK ,
NO BEFORE JOURNAL,
NO AFTER JOURNAL,
CHECKSUM = DEFAULT,
DEFAULT MERGEBLOCKRATIO
(
col1 INTEGER,
col2 INTEGER,
col3 INTEGER
)
NO PRIMARY INDEX ;
WITH
cteTable3 AS
( SELECT A.colA, A.colB, A.colC, B.col1, B.col2, B.col3
FROM cteTable1 A INNER JOIN cteTable2 ON (blah blah blah) ),
cteTable2 AS
( SELECT col1, col2, col3 FROM SourceTableB ),
cteTable1 AS
( SELECT colA, colB, colC FROM SourceTableA )
INSERT INTO dbname.physicalTablename
( col1, col2, col3, col4, col5, col6 )
SELECT
(C3.colA, C3.colB, C3.colC, C3.col1, C3.col2, C3.col3)
FROM cteTable3 C3 ;
While you are missing the INSERT portion of the question, I think the following might clear things up. The correct format for using a CTE in an INSERT is:
INSERT INTO <tablename>
WITH <cte> AS (SELECT...)
SELECT <fields> FROM <cte>
Consider the following:
CREATE MULTISET VOLATILE TABLE tmp AS (SELECT 'bobby' as firstname) WITH DATA ON COMMIT PRESERVE ROWS;
INSERT INTO tmp
WITH cte AS (select 'carol' as firstname)
SELECT * FROM cte;
SELECT * FROM tmp;
DROP TABLE tmp;

How to put 2 rows returned from a query into into 2 columns of a single row in Oracle sql

I run a query that returns 2 rows
SELECT a FROM TABLE-A WHERE condition=something;
row1 Value1
row2 Value2
Now, I want to put it in a new table in 2 columns of a single row
SELECT column1, column2 FROM TABLE-B WHERE condition=something;
row1 column1 column2
value1 value2
Can you please help me with this?
It is unclear how you want to pick which row goes into which column - here are a couple of options:
SELECT MIN( a ) AS minimum_value,
MAX( a ) AS maximum_value
FROM table_a
WHERE 1=1;
or
SELECT MAX( a ) KEEP ( DENSE_RANK FIRST ORDER BY ROWNUM ) AS first_value,
MAX( a ) KEEP ( DENSE_RANK LAST ORDER BY ROWNUM ) AS last_value
FROM table_a
WHERE 1=1;
or
SELECT *
FROM ( SELECT a, ROWNUM AS rn FROM table_a WHERE 1=1 )
PIVOT ( MAX(a) FOR rn IN ( 1 AS first_value, 2 AS second_value ) );

How to display data with pivot in oracle?

I stuck an hours to display the data in weekly result, but I'm always fail to display that. I'm new in pivot.
Please help me.
Thank you!
Sample data need to produce:
Data,03/10/2014,200,150,186,172
Data,03/16/2014,144,115,181,157
Data,03/22/2014,130,198,136,393
Here's the script:
select 'Data,'''
||(
select listagg(SIM_id,''',''') within group (order by 1)
from (
select distinct substr(dst_channel,1,14) as SIM_id
from table1
where dst_channel like 'SIP/item__-%'
)
)
from dual;
select 'Data'
||','||dtime_day
||','||g1_cnt
||','||g2_cnt
||','||g3_cnt
||','||g4_cnt
from (
select 'Data'
,to_char(d.dtime_day,'MM/dd/yyyy') as dtime_day
,substr(c.dst_channel,1,14) as dst_channel
from table2 d
left join table1
on c.call_date = d.dtime_day
where c.dst_channel like 'SIP/item%'
and c.status like 'ANSWERED%'
and d.dtime_day between trunc(sysdate, 'IW')-(12*7) and trunc(sysdate) -1
)
pivot(
count(dst_channel) as cnt
for dst_channel in (
'SIP/item01' as g1,'SIP/item02' as g2,'SIP/item03' as g3,'SIP/item04' as g4
)
)
order by dtime_day
Result of the query above:
Data,03/10/2014,147,103,86,76
Data,03/11/2014,144,115,81,57
Data,03/12/2014,130,98,59,39

How to display comma separated descriptions based on comma separated values in Oracle 10g?

I am new to Oracle technology. Earlier I posted 2 posts for the same issue due to lack of understanding the requirement.
Table 1:
MSGID
-----
1,2,3
2,3
4
null
null
Table 2:
MID MSGDESC
---- -------
1 ONE
2 TWO
3 THREE
4 FOUR
Expected output:
XCOL DESC
----- -----
1,2,3 ONE,TWO,THREE
2,3 TWO,THREE
4 FOUR
I am not able to fulfil this requirement. Please provide me one solution.
Note: tables don't have any unique or primary key values. Table 1 has 5000 records and table 2 only has 80 records with descriptions.
create table Table1 (MSGID varchar2(100));
insert into Table1 values ('1,2,3');
insert into Table1 values ('2,3');
insert into Table1 values ('4');
insert into Table1 values (null);
insert into Table1 values (null);
create table Table2 (MID varchar2(100), MSGDESC varchar2(100));
insert into Table2 values ('1','ONE');
insert into Table2 values ('2','TWO');
insert into Table2 values ('3','THREE');
insert into Table2 values ('4','FOUR');
select
msgid as xcol,
"DESC",
col1, col2, ..., col12
from
Table1
left join (
select
msgid,
wm_concat(msgdesc) as "DESC"
from
(
select
msgid,
msgdesc
from
(select distinct msgid from Table1 where ...)
cross join (
select level as occ from dual connect by level <= 100)
)
left join Table2
on mid = regexp_substr(msgid, '[^,]+', 1, occ)
where
occ <= regexp_count(msgid, ',') + 1
order by msgid, occ
)
group by msgid
) using (msgid)

Resources