Oracle Pivoting returning Null values for Month/Year - oracle

I'm trying to pivoting this table by month/year according to date (field DT):
CREATE TABLE "TEMP"
( "NAME" VARCHAR2(20 BYTE),
"DT" DATE,
"SZ" NUMBER(10,0)
)
Insert into TEMP (NAME,DT,SZ) values ('A',to_date('16/01/15','DD/MM/RR'),'1');
Insert into TEMP (NAME,DT,SZ) values ('B',to_date('16/01/15','DD/MM/RR'),'2');
Insert into TEMP (NAME,DT,SZ) values ('C',to_date('16/01/15','DD/MM/RR'),'3');
Insert into TEMP (NAME,DT,SZ) values ('D',to_date('16/01/15','DD/MM/RR'),'4');
Insert into TEMP (NAME,DT,SZ) values ('A',to_date('10/01/15','DD/MM/RR'),'5');
Insert into TEMP (NAME,DT,SZ) values ('B',to_date('10/01/15','DD/MM/RR'),'6');
Insert into TEMP (NAME,DT,SZ) values ('C',to_date('10/01/15','DD/MM/RR'),'7');
using this query:
SELECT * from
(select name, sz, dt from temp)
pivot (sum(sz) for dt in (to_date('01/2015', 'MM/YYYY') as "dt"))
and I receive this:
NAME dt
-------------------- ----------
D
A
B
C
However, I was excepting to get:
NAME dt
-------------------- ----------
D 4
A 6
B 8
C 10
I've tried many things but none of them seems to work as:
...
pivot (sum(sz) for dt in ('01/2015' as "dt")) --01843. 00000 - "not a valid month"
Do you have a clue of what I'm doing wrong?
Any help is very welcome.

You need to use TO_CHAR and not TO_DATE
WITH pivotdata AS
(
SELECT name,
sz,
To_char(dt, 'MM/YYYY') dt1
FROM temp )
SELECT *
FROM pivotdata pivot (SUM(sz) FOR dt1 IN ('01/2015') );
This will return
NAME '01/2015'
D 4
A 6
B 8
C 10

Related

Convert Oracle to Hive - SubQuery can contain only 1 item in Select List

Code and sample data to try on your system:
CREATE TABLE "EMP"
( "DR_SID" NUMBER,
"DR_NAME" VARCHAR2(50 BYTE) COLLATE "USING_NLS_COMP",
"ACTIVE_FLAG" VARCHAR2(1 BYTE) COLLATE "USING_NLS_COMP",
"LAST_UPDATED_TIME" TIMESTAMP (6),
"DATA_SOURCE" VARCHAR2(100 BYTE) COLLATE "USING_NLS_COMP",
"ROW_LIMIT" VARCHAR2(50 BYTE) COLLATE "USING_NLS_COMP",
"VERSION#" NUMBER,
"PARENT_DR_SID" NUMBER
)
;
REM INSERTING into EMP
SET DEFINE OFF;
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (1,'this should not come1',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,1);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (2,'come',to_timestamp('19-SEP-20 07.18.56.271199000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,2);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (3,'come123',to_timestamp('13-FEB-21 05.05.51.645956000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,3);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (4,'come456',to_timestamp('13-FEB-21 05.05.51.951505000 AM','DD-MON-RR HH.MI.SSXFF AM'),1,4);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (5,'this should not come2',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),2,1);
Insert into EMP (DR_SID,DR_NAME,LAST_UPDATED_TIME,VERSION#,PARENT_DR_SID) values (6,'this should COME',to_timestamp('18-APR-20 05.05.52.425734000 AM','DD-MON-RR HH.MI.SSXFF AM'),3,1);
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID FROM emp ;
the below query needs to be converted into Hive, can someone help?
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID FROM emp t
where (version#,parent_dr_sid)
in (select max(version#),parent_dr_sid from emp group by parent_dr_sid)
;
I am try to find out which record is latest, so am using version# column (if
version# column has the max value then the record is latest and its previous records are old and not to display).
Now how the records are linked with each other, so we have two columns, dr_sid is pk and parent_dr_sid contains same value to show this record is linked with which old record.
you can see the example here, in the given sample code, dr_sid = 1 is present 3 times in parent_dr_sid, all these 3 records
of parent_dr_sid have the same value as 1 (which is linked to dr_sid).
Now I want the below o/p, can you do the same in hive?
FYI - we cant update the table so trying to update the record in this way and fetching in this way.
DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#, PARENT_DR_SID
1 this should not come1 18-APR-20 05.05.52.425734000 AM 1 1
2 come 19-SEP-20 07.18.56.271199000 AM 1 2
3 come123 13-FEB-21 05.05.51.645956000 AM 1 3
4 come456 13-FEB-21 05.05.51.951505000 AM 1 4
5 this should not come2 18-APR-20 05.05.52.425734000 AM 2 1
6 this should COME 18-APR-20 05.05.52.425734000 AM 3 1
Use left semi join to emulate in semantics for tuples.
with input as (
select inline(array(
(1,1),
(1,2),
(2,1),
(2, 2)
)) as (c1, c2)
)
, flt as (
select inline(array(
(1,1),
(2, 2)
)) as (f1, f2)
)
select *, split(version(), ' ')[0] as v
from input
left semi join flt
on input.c1 = flt.f1
and input.c2 = flt.f2
input.c1
input.c2
v
1
1
3.1.3000.7.1.7.0-551
2
2
3.1.3000.7.1.7.0-551
I don't know Hive so these might well be completely useless suggestions; however, see if it helps.
If you can use a subquery in FROM clause, you might do the following:
select e.*
from emp e join (select max(a.create_tm) create_tm, a.open_dt
from emp a group by a.open_dt
) x
on x.create_tm = e.create_tm
and x.open_dt = e.open_dt;
Or, make your subquery return a single column by concatenating values. They look like "time" and "date" (I don't know their datatypes so you might need to apply e.g. TO_CHAR function to these columns; no problem in that, as long as it returns desired result):
select *
from emp
where concat(create_tm, open_dt) in (select concat(max(create_tm), open_dt)
from emp
group by open_dt);
this is working:
SELECT DR_SID, DR_NAME, LAST_UPDATED_TIME, VERSION#--, PARENT_DR_SID
FROM emp t join
(select max(version#) v,parent_dr_sid from emp group by parent_dr_sid) t2
on t.version#=t2.v and t.parent_dr_sid = t2.parent_dr_sid
;

insert all and inner join in oracle

I would like to insert data in to two tables. Will be one-to-many connection. For this, I have to use Foreign Key, of course.
I think, table1 - ID column is an ideal for this a Primary Key. But I generate it always with a trigger, automatically, every line. SO,
How can I put Table1.ID (auto generated, Primary Key) column in to table2.Fkey column in the same insert query?
INSERT ALL INTO table1 ( --here (before this) generated the table1.id column automatically with a trigger.
table1.food,
table1.drink,
table1.shoe
) VALUES (
'apple',
'water',
'slippers'
)
INTO table2 (
fkey,
color
) VALUES (
table1.id, -- I would like table2.fkey == table1.id this gave me error
'blue'
) SELECT
*
FROM
table1
INNER JOIN table2 ON table1.id = table2.fkey;
The error message:
"00904. 00000 - "%s: invalid identifier""
As suggested by #OldProgrammer, use sequence
INSERT ALL INTO table1 ( --here (before this) generated the table1.id column automatically with a trigger.
table1_id,
table1.food,
table1.drink,
table1.shoe
) VALUES (
<sequecename_table1>.nextval,
'apple',
'water',
'slippers'
)
INTO table2 (
fkey,
color
) VALUES (
<sequecename_table2>.nextval,
<sequecename_table1>.currval, -- returns the current value of a sequence.
'blue'
) SELECT
*
FROM
table1
INNER JOIN table2 ON table1.id = table2.fkey;
Since you're using Oracle DB's 12c version, then might use Identity Column Property. Then easily return the value of first table's (table1) to a local variable by charging of returning clause just after an insert statement for table1, and use inside the next insert statement which is for table2 as stated below :
SQL> create table table1(
2 ID integer generated always as identity primary key,
3 food varchar2(50), drink varchar2(50), shoe varchar2(50)
4 );
SQL> create table table2(
2 fkey integer references table1(ID),
3 color varchar2(50)
4 );
SQL> declare
2 cl_tab table1.id%type;
3 begin
4 insert into table1(food,drink,shoe) values('apple','water','slippers' )
5 returning id into cl_tab;
6 insert into table2 values(cl_tab,'blue');
7 end;
8 /
SQL> select * from table1;
ID FOOD DRINK SHOE
-- ------- ------- -------
1 apple water slippers
SQL> select * from table2;
FKEY COLOR
---- --------------------------------------------------
1 blue
Anytime you issue the above statement for insertions between begin and end, both table1.ID and table2.fkey columns will be populated by the same integer values. By the way do not forget to commit the changes by insertions, if you need these values throughout the DB(i.e.from other sessions also).

Oracle How to return a string in a particular format

I have one requirement where i want to return output in a particular format based on one column(Idx). In one column we have date range based on that loop should execute.
drop table t_table_test;
create table t_table_test ( ID NUMBER, NM VARCHAR2(4000), VAL VARCHAR2(4000), IDX NUMBER);
select * from t_table_test;
INSERT INTO t_table_test VALUES (1,'CNTRY', 'USA',1);
INSERT INTO t_table_test VALUES (1,'DT', '2017-01-01,2017-01-02',2);
INSERT INTO t_table_test VALUES (1,'PART', 'NA',3);
If Input is below
ID NM VAL IDX
1 CNTRY USA 1
1 DT 2017-01-01,2017-01-02 2
1 PART NA 3
Output should be this will be based on IDX column
CNTRY:USA,DT:2017-01-01,PART:NA?CNTRY:USA,DT:2017-01-02,PART:NA
I/P
ID NM VAL IDX
1 DT 2017-01-01,2017-01-02 1
1 CNTRY USA 2
1 PART NA 3
DT:2017-01-01,CNTRY:USA,PART:NA?DT:2017-01-02,CNTRY:USA,PART:NA
DELETE FROM t_table_test WHERE idx=3;
commit;
O/P DT:2017-01-01,CNTRY:USA?DT:2017-01-02,CNTRY:USA
DELETE FROM t_table_test WHERE idx=1;
commit;
O/P DT:2017-01-01?DT:2017-01-02
Need query which work in all above cases .
Perhaps you can try this:
select rtrim(XMLAGG(XMLELEMENT(E,val||'?')).EXTRACT('//text()'),',') from (
with dates as (SELECT distinct NM||':'||trim(regexp_substr(val, '[^,]+', 1, level)) val
from t_table_test where nm='DT' CONNECT BY instr(val, ',', 1, level - 1) > 0),
parts as (select NM||':'||VAL val FROM t_table_test where nm='PART')
SELECT NM||':'||t.VAL||','||d.VAL||','||p.val val from t_table_test t, dates d, parts p
where NM='CNTRY');
It does rely on the names being fixed - having only DT being a comma separated list of values, for instance - but I think it might help you format your results. You can use this as a basis for building many similar formatting solutions.

Oracle Query: Get distinct names having count greater than a threshold

I have a table having schema given below
EmpID,MachineID,Timestamp
1, A,01-Nov-13
2, A,02-Nov-13
3, C,03-Nov-13
1, B,02-Nov-13
1, C,04-Nov-13
2, B,03-Nov-13
3, A,02-Nov-13
Desired Output:
EmpID,MachineID
1, A
1, B
1, C
2, A
2, B
3, A
3, C
So basically, I want to find the Emp who have used more than one machines in the given time period.
The query I am using is
select EmpID,count(distinct(MachineID)) from table
where Timestamp between '01-NOV-13' AND '07-NOV-13'
group by EmpID having count(distinct(MachineID)) > 1
order by count(distinct(MachineID)) desc;
This query is given me output like this
EmpID,count(distinct(MachineID))
1, 3
2, 2
3, 2
Can anyone help with making changes to get the output like described above in my question.
One possible solution:
CREATE TABLE emp_mach (
empid NUMBER,
machineid VARCHAR2(1),
timestamp_val DATE
);
INSERT INTO emp_mach VALUES (1,'A', DATE '2013-11-01');
INSERT INTO emp_mach VALUES (2,'A', DATE '2013-11-02');
INSERT INTO emp_mach VALUES (3,'C', DATE '2013-11-03');
INSERT INTO emp_mach VALUES (1,'B', DATE '2013-11-02');
INSERT INTO emp_mach VALUES (1,'C', DATE '2013-11-04');
INSERT INTO emp_mach VALUES (2,'B', DATE '2013-11-03');
INSERT INTO emp_mach VALUES (3,'A', DATE '2013-11-02');
COMMIT;
SELECT DISTINCT empid, machineid
FROM emp_mach
WHERE empid IN (
SELECT empid
FROM emp_mach
WHERE timestamp_val BETWEEN DATE '2013-11-01' AND DATE '2013-11-07'
GROUP BY empid
HAVING COUNT(DISTINCT machineid) > 1
)
ORDER BY empid, machineid;
(I've changed the name of the timestamp column to timestamp_val)
Output:
EMPID MACHINEID
---------- ---------
1 A
1 B
1 C
2 A
2 B
3 A
3 C
you did the hardest. Your query has to be used to filter out the results:
SELECT t1.empid, t1.machineid
FROM
table t1
WHERE
EXIST (
SELECT
empid
FROM table t2
WHERE
timestamp BETWEEN '01-NOV-13' AND '07-NOV-13'
AND t2.empid = t1.empid
GROUP BY empid HAVING COUNT(distinct(machineid)) > 1
)
ORDER BY empid, machineid;
edit: posted a few secs after Przemyslaw Kruglej. I'll leave it here since it is just another alternative (using EXIST instead of IN)
SELECT * FROM
(SELECT DISTINCT(EmpID),COUNT(*) AS NumEMP
from TableA
WHERE Timestamp between '01-NOV-13' AND '07-NOV-13'
group by EmpID
order by EmpID
)
WHERE NumEmp >= 1

select values from table and create oracle objects

i want to insert values to oracle Object type by selecting values from other table
And the tables and insert statement looks like this.
CREATE TYPE Test_obj AS OBJECT (
attr1 VARCHAR2(20),
attr2 VARCHAR2(20),
attr3 VARCHAR2(25) );
/
CREATE TABLE resultrow_obj (
resultrow Test_obj ,
RESULTTABLEID NUMBER(20,0),
ROWNUMBER NUMBER(20,0) );
/
INSERT INTO resultrow_obj VALUES (
Test_obj (select col1,col2,col3 from Table2 where rownum<=1),
1,123 );
/
You've got it nearly right:
SQL> INSERT INTO resultrow_obj
2 VALUES((SELECT Test_obj('A', 'B', 'C')
3 FROM dual WHERE rownum <= 1),
4 1, 123);
1 row inserted

Resources