Need row data column wise in oracle - sql

I need to compare prices coming from 3 sources (27, 2, 55) from owners column. i am not sure if i should use select sub query or left join ?
Desired Result

Looks like a pivot.
Sample data in lines #1 - 10; query you might need begins at line #12.
SQL> with test (id_value, as_of, timezone, price, owner) as
2 -- sample data
3 (select 'EEM.A', date '2021-06-25', 'J1530', 55.04, 55 from dual union all
4 select 'EEM.A', date '2021-06-25', 'J1530', 55.04, 27 from dual union all
5 select 'EEM.A', date '2021-06-25', 'J1530', 55.04, 2 from dual union all
6 --
7 select 'AMX.N', date '2021-06-25', 'J1530', 15.4, 55 from dual union all
8 select 'AMX.N', date '2021-06-25', 'J1530', 15.4, 27 from dual union all
9 select 'AMX.N', date '2021-06-25', 'J1530', 15.4, 2 from dual
10 )
11 -- query begins here
12 select *
13 from test
14 pivot (max(price)
15 for owner in (55, 27, 2)
16 );
ID_VA AS_OF TIMEZ 55 27 2
----- ---------- ----- ---------- ---------- ----------
AMX.N 06/25/2021 J1530 15,4 15,4 15,4
EEM.A 06/25/2021 J1530 55,04 55,04 55,04
SQL>

Related

I do need help in writing SQL Query in ORACLE for the below sample data [duplicate]

This question already has answers here:
Second highest grade for each student
(3 answers)
Closed 3 months ago.
My data looks like below:
table
REF_NUM ID DATE
SIM1 1 12-Oct-22
SIM1 2 10-Oct-22
SIM2 3 15-Oct-22
SIM2 4 14-Oct-22
SIM3 5 08-Oct-22
SIM3 6 02-Oct-22
SIM4 7 08-Oct-22
SIM4 8 10-Oct-22
Output should be as below:
Output:
REF_NUM ID DATE
SIM1 2 10-Oct-22
SIM2 4 14-Oct-22
SIM3 6 02-Oct-22
SIM4 7 08-Oct-22
basically I need data with distinct ref_num , respective ID and with SECOND HIGHEST DATE. Here I have just given two dates in main table, But each ref_num can have more than two dates.
I can sure that whatever I have tried is wrong
Rank rows per each ref_num by the date datatype value in descending order; then fetch these that rank as the second highest.
Sample data:
SQL> with test (ref_num, id, datum) as
2 (select 'sim1', 1, date '2022-10-12' from dual union all
3 select 'sim1', 2, date '2022-10-10' from dual union all
4 select 'sim2', 3, date '2022-10-15' from dual union all
5 select 'sim2', 4, date '2022-10-14' from dual union all
6 select 'sim3', 5, date '2022-10-08' from dual union all
7 select 'sim3', 6, date '2022-10-02' from dual union all
8 select 'sim4', 7, date '2022-10-08' from dual union all
9 select 'sim4', 8, date '2022-10-10' from dual
10 ),
Query begins here:
11 temp as
12 (select ref_num, id, datum,
13 rank() over (partition by ref_num order by datum desc) rnk
14 from test
15 )
16 select ref_num, id, datum
17 from temp
18 where rnk = 2
19 order by ref_num;
REF_ ID DATUM
---- ---------- ----------
sim1 2 10.10.2022
sim2 4 14.10.2022
sim3 6 02.10.2022
sim4 7 08.10.2022
SQL>

sql query need to check date along with Store_id

I have two tables, both has millions of rows.
Table A:-
Store_id, Purchase_dt, Amount
-------- ----------- ------
1001 02JAN19 12.20
1001 05MAY20 13.30
1002 07JUL21 10.97
Table B:-
Store_id, Valid_from, Valid_to, Profile_ID
-------- ---------- -------- ----------
1001 01JAN17 08JUL19 56
1001 09JUL19 12DEC99 60
1002 01JAN20 12DEC99 70
I need to find only transaction from stores that has a profile id of 60 and 70 and Purchase_dt should be between Valid_from and valid_to and for this joining column is Store_id.
Target table expectation is:
Store_id, Purchase_dt, Amount, Profile_ID
-------- ----------- ------
1001 05MAY20 13.30 60
1002 07JUL21 10.97 70
I tried with
Select
a.Store_id,
a.Purchase_dt,
a.Amount,
b.Profile_ID
from
table_a a,
table_b b
where
a.Store_id = b.Store_id
and
a.Purchase_dt between b.Valid_from and b.Valid_to
and
b.Profile_ID in (60,70)
but not getting the desired result, all dates are date data type any help is appreciated!
If dates are really stored as strings (that's what sample data you posted looks like), then - if you want between to work properly - you first have to convert these strings into valid DATE datatype values (using to_date function with appropriate format model).
Moreover, you're looking for trouble keeping 2-digits years; didn't Y2K bug teach you anything?
I'd suggest you to keep dates in DATE datatype columns and avoid many kinds of problems.
As of your current problem, here you are:
Sample data:
SQL> with
2 table_a (store_id, purchase_dt, amount) as
3 (select 1001, '02JAN19', 12.20 from dual union all
4 select 1001, '05MAY20', 13.30 from dual union all
5 select 1002, '07JUL21', 10.97 from dual
6 ),
7 table_b (store_id, valid_from, valid_to, profile_id) as
8 (select 1001, '01JAN17', '08JUL19', 56 from dual union all
9 select 1001, '09JUL19', '12DEC99', 60 from dual union all
10 select 1002, '01JAN20', '12DEC99', 70 from dual
11 )
Query begins here:
12 select a.store_id, a.purchase_dt, a.amount, b.profile_id
13 from table_a a join table_b b
14 on a.store_id = b.store_id
15 and to_date(a.purchase_dt, 'ddMONyy') between
16 to_date(b.valid_from, 'ddMONyy') and to_date(b.valid_to, 'ddMONyy')
17 where b.profile_id in (60, 70);
STORE_ID PURCHAS AMOUNT PROFILE_ID
---------- ------- ---------- ----------
1001 05MAY20 13,3 60
1002 07JUL21 10,97 70
SQL>
If - as you commented - date values really are DATEs - then it gets simpler.
Compare:
Strings:
15 and to_date(a.purchase_dt, 'ddMONyy') between
16 to_date(b.valid_from, 'ddMONyy') and
to_date(b.valid_to, 'ddMONyy')
Dates:
15 and a.purchase_dt between b.valid_from and b.valid_to
The whole query that deals with DATE datatype:
SQL> with
2 table_a (store_id, purchase_dt, amount) as
3 (select 1001, date '2019-01-02', 12.20 from dual union all
4 select 1001, date '2020-05-05', 13.30 from dual union all
5 select 1002, date '2021-07-07', 10.97 from dual
6 ),
7 table_b (store_id, valid_from, valid_to, profile_id) as
8 (select 1001, date '2017-01-01', date '2019-07-08', 56 from dual union all
9 select 1001, date '2019-07-09', date '2099-12-12', 60 from dual union all
10 select 1002, date '2020-01-01', date '2099-12-12', 70 from dual
11 )
12 select a.store_id, a.purchase_dt, a.amount, b.profile_id
13 from table_a a join table_b b
14 on a.store_id = b.store_id
15 and a.purchase_dt between b.valid_from and b.valid_to
16 where b.profile_id in (60, 70) ;
STORE_ID PURCHASE AMOUNT PROFILE_ID
---------- -------- ---------- ----------
1001 05.05.20 13,3 60
1002 07.07.21 10,97 70
SQL>
Your query applied to same sample data also works:
SQL> with
2 table_a (store_id, purchase_dt, amount) as
3 (select 1001, date '2019-01-02', 12.20 from dual union all
4 select 1001, date '2020-05-05', 13.30 from dual union all
5 select 1002, date '2021-07-07', 10.97 from dual
6 ),
7 table_b (store_id, valid_from, valid_to, profile_id) as
8 (select 1001, date '2017-01-01', date '2019-07-08', 56 from dual union all
9 select 1001, date '2019-07-09', date '2099-12-12', 60 from dual union all
10 select 1002, date '2020-01-01', date '2099-12-12', 70 from dual
11 )
This is your query:
12 Select
13 a.Store_id,
14 a.Purchase_dt,
15 a.Amount,
16 b.Profile_ID
17 from
18 table_a a,
19 table_b b
20 where
21 a.Store_id = b.Store_id
22 and
23 a.Purchase_dt between b.Valid_from and b.Valid_to
24 and
25 b.Profile_ID in (60,70);
STORE_ID PURCHASE AMOUNT PROFILE_ID
---------- -------- ---------- ----------
1001 05.05.20 13,3 60
1002 07.07.21 10,97 70
SQL>

How to count number of records for each week, from last month activity on a table?

I'm working with Oracle and I have a table with a column of type TIMESTAMP. I was wondering how can I extract the records from last 4 weeks of activity on the database, partitioned by week.
Following rows are inserted on week 1
kc 2 04-10-2021
vc 3 06-10-2021
vk 4 07-10-2021
Following rows are inserted on week2
cv 1 12-10-2021
ck 5 14-10-2021
Following rows are inserted on week3
vv 7 19-10-2021
Following rows are inserted on week4
vx 7 29-10-2021
Table now has
SQL>select * from tab;
NAME VALUE TIMESTAMP
-------------------- ----------
kc 2 04-10-2021
vc 3 06-10-2021
vk 4 07-10-2021
cv 1 12-10-2021
ck 5 14-10-2021
vv 7 19-10-2021
vx 7 29-10-2021
I would like a query which would give me the number of rows added each week, in the last 4 weeks.
This is what I would like to see
numofrows week
--------- -----
3 1
2 2
1 3
1 4
One option is to use to_char function and its iw parameter:
SQL> with test (name, datum) as
2 (select 'kc', date '2021-10-04' from dual union all
3 select 'vc', date '2021-10-06' from dual union all
4 select 'vk', date '2021-10-07' from dual union all
5 select 'cv', date '2021-10-12' from dual union all
6 select 'ck', date '2021-10-14' from dual union all
7 select 'vv', date '2021-10-19' from dual union all
8 select 'vx', DATE '2021-10-29' from dual
9 )
10 select to_char(datum, 'iw') week,
11 count(*)
12 from test
13 where datum >= add_months(sysdate, -1) --> the last month
14 group by to_char(datum, 'iw');
WE COUNT(*)
-- ----------
42 1
43 1
40 3
41 2
SQL>
Line #13: I intentionally used "one month" instead of "4 weeks" as I thought (maybe wrongly) that you, actually, want that (you know, "a month has 4 weeks" - not exactly, but close, sometimes not close enough).
If you want 4 weeks, what is that, then? Sysdate minus 28 days (as every week has 7 days)? Then you'd modify line #13 to
where datum >= trunc(sysdate - 4*7)
Or, maybe it is really the last 4 weeks:
SQL> with test (name, datum) as
2 (select 'kc', date '2021-10-04' from dual union all
3 select 'vc', date '2021-10-06' from dual union all
4 select 'vk', date '2021-10-07' from dual union all
5 select 'cv', date '2021-10-12' from dual union all
6 select 'ck', date '2021-10-14' from dual union all
7 select 'vv', date '2021-10-19' from dual union all
8 select 'vx', DATE '2021-10-29' from dual
9 ),
10 temp as
11 (select to_char(datum, 'iw') week,
12 count(*) cnt,
13 row_number() over (order by to_char(datum, 'iw') desc) rn
14 from test
15 group by to_char(datum, 'iw')
16 )
17 select week, cnt
18 from temp
19 where rn <= 4
20 order by week;
WE CNT
-- ----------
40 3
41 2
42 1
43 1
SQL>
Now you have several options, see which one fits the best (if any).
I "simulated" missing data (see TEST CTE), created a calendar (calend) and ... did the job. Read comments within code:
SQL> with test (name, datum) as
2 -- sample data
3 (select 'vv', date '2021-10-19' from dual union all
4 select 'vx', DATE '2021-10-29' from dual
5 ),
6 calend as
7 -- the last 31 days; 4 weeks are included, obviously
8 (select max_datum - level + 1 datum
9 from (select max(a.datum) max_datum from test a)
10 connect by level <= 31
11 ),
12 joined as
13 -- joined TEST and CALEND data
14 (select to_char(c.datum, 'iw') week,
15 t.name
16 from calend c left join test t on t.datum = c.datum
17 ),
18 last4 as
19 -- last 4 weeks
20 (select week, count(name) cnt,
21 row_number() over (order by week desc) rn
22 from joined
23 group by week
24 )
25 select week, cnt
26 from last4
27 where rn <= 4
28 order by week;
WE CNT
-- ----------
40 0
41 0
42 1
43 1
SQL>

Oracle SQL - return the date record when there is no count result

I have the tables below and I need my query to bring me the amount of operations grouped by date.
For the dates on which there will be no operations, I need to return the date anyway with the zero count.
Kind like that:
OPERATION_DATE | COUNT_OPERATION | COUNT_OPERATION2 |
04/06/2019 | 453 | 81 |
05/06/2019 | 0 | 0 |
-- QUERY I TRIED
SELECT
T1.DATE_OPERATION AS DATE_OPERATION,
NVL(T1.COUNT_OPERATION, '0') COUNT_OPERATION,
NVL(T1.COUNT_OPERATION2, '0') COUNT_OPERATIONX,
FROM
(
SELECT
trunc(t.DATE_OPERATION) as DATE_OPERATION,
count(t.ID_OPERATION) AS COUNT_OPERATION,
COUNT(CASE WHEN O.OPERATION_TYPE = 'X' THEN 1 END) COUNT_OPERATIONX,
from OPERATION o
left join OPERATION_TYPE ot on ot.id_operation = o.id_operation
where ot.OPERATION_TYPE in ('X', 'W', 'Z', 'I', 'J', 'V')
and TRUNC(t.DATE_OPERATION) >= to_date('01/06/2019', 'DD-MM-YYYY')
group by trunc(t.DATE_OPERATION)
) T1
-- TABLES
CREATE TABLE OPERATION
( ID_OPERATION NUMBER NOT NULL,
DATE_OPERATION DATE NOT NULL,
VALUE NUMBER NOT NULL )
CREATE TABLE OPERATION_TYPE
( ID_OPERATION NUMBER NOT NULL,
OPERATION_TYPE VARCHAR2(1) NOT NULL,
VALUE NUMBER NOT NULL)
I guess that it is a calendar you need, i.e. a table which contains all dates involved. Otherwise, how can you display something that doesn't exist?
This is what you currently have (I'm using only the operation table; add another one yourself):
SQL> with
2 operation (id_operation, date_operation, value) as
3 (select 1, date '2019-06-01', 100 from dual union all
4 select 2, date '2019-06-01', 200 from dual union all
5 -- 02/06/2019 is missing
6 select 3, date '2019-06-03', 300 from dual union all
7 select 4, date '2019-06-04', 400 from dual
8 )
9 select o.date_operation,
10 count(o.id_operation)
11 from operation o
12 group by o.date_operation
13 order by o.date_operation;
DATE_OPERA COUNT(O.ID_OPERATION)
---------- ---------------------
01/06/2019 2
03/06/2019 1
04/06/2019 1
SQL>
As there are no rows that belong to 02/06/2019, query can't return anything (you already know that).
Therefore, add a calendar. If you already have that table, fine - use it. If not, create one. It is a hierarchical query which adds level to a certain date. I'm using 01/06/2019 as the starting point, creating 5 days (note the connect by clause).
SQL> with
2 operation (id_operation, date_operation, value) as
3 (select 1, date '2019-06-01', 100 from dual union all
4 select 2, date '2019-06-01', 200 from dual union all
5 -- 02/06/2019 is missing
6 select 3, date '2019-06-03', 300 from dual union all
7 select 4, date '2019-06-04', 400 from dual
8 ),
9 dates (datum) as --> this is a calendar
10 (select date '2019-06-01' + level - 1
11 from dual
12 connect by level <= 5
13 )
14 select d.datum,
15 count(o.id_operation)
16 from operation o full outer join dates d on d.datum = o.date_operation
17 group by d.datum
18 order by d.datum;
DATUM COUNT(O.ID_OPERATION)
---------- ---------------------
01/06/2019 2
02/06/2019 0 --> missing in source table
03/06/2019 1
04/06/2019 1
05/06/2019 0 --> missing in source table
SQL>
Probably a better option is to dynamically create a calendar so that it doesn't depend on any hardcoded values, but uses the min(date_operation) to max(date_operation) time span. Here we go:
SQL> with
2 operation (id_operation, date_operation, value) as
3 (select 1, date '2019-06-01', 100 from dual union all
4 select 2, date '2019-06-01', 200 from dual union all
5 -- 02/06/2019 is missing
6 select 3, date '2019-06-03', 300 from dual union all
7 select 4, date '2019-06-04', 400 from dual
8 ),
9 dates (datum) as --> this is a calendar
10 (select x.min_datum + level - 1
11 from (select min(o.date_operation) min_datum,
12 max(o.date_operation) max_datum
13 from operation o
14 ) x
15 connect by level <= x.max_datum - x.min_datum + 1
16 )
17 select d.datum,
18 count(o.id_operation)
19 from operation o full outer join dates d on d.datum = o.date_operation
20 group by d.datum
21 order by d.datum;
DATUM COUNT(O.ID_OPERATION)
---------- ---------------------
01/06/2019 2
02/06/2019 0 --> missing in source table
03/06/2019 1
04/06/2019 1
SQL>

Oracle SQL Query for monthwise report

Guys i have a table called A which has columns as
-----
A
-----
S_DATE
DUR
VIEWS
AMOUNT
The data in the table A has the following rows which is DateWise.
20101023 12 1 10000.0
20101101 2 4 200.0
20101114 4 5 -9
20101201 6 10 150.0
20101219 1 12 130.0
My requirement is that i want to write an SQL query that does monthwise *report*. For example from webGUI , when i select on the dropdown for month as DEC and select year as 2010 . I need to create show the sum of DUR,VIEWS and AMOUNT from 1st of November 2010 to 1st of December 2010.Any Ideas on how to do it.
The result for DEC2010 should be like below
**DEC2010 12 19 341**
this would work (although of course due to your requirement the first day of november will be in both the november and december monthly reports ?!):
SQL> VARIABLE p_months VARCHAR2(3);
SQL> VARIABLE p_year NUMBER;
SQL> EXEC :p_months := 'DEC'; :p_year := 2010;
PL/SQL procedure successfully completed.
SQL> WITH tableA AS (
2 SELECT DATE '2010-10-23's_date , 12 dur, 1 views, 10000.0 amount FROM DUAL
3 UNION ALL SELECT DATE '2010-11-01', 2, 4 , 200.0 FROM DUAL
4 UNION ALL SELECT DATE '2010-11-14', 4, 5 , -9 FROM DUAL
5 UNION ALL SELECT DATE '2010-12-01', 6, 10, 150.0 FROM DUAL
6 UNION ALL SELECT DATE '2010-12-19', 1, 12, 130.0 FROM DUAL
7 )
8 SELECT :p_months||:p_year month,
9 SUM(dur),
10 SUM(views),
11 SUM(amount)
12 FROM tableA
13 WHERE s_date >= add_months(to_date(:p_months||:p_year, 'MONYYYY'), -1)
14 AND s_date < to_date(:p_months||:p_year, 'MONYYYY') + 1;
MONTH SUM(DUR) SUM(VIEWS) SUM(AMOUNT)
---------- ---------- ---------- -----------
DEC2010 12 19 341