Get subobject of object in hierarchy - oracle

with sample_data as (select '26.03.2015 14:10' as adate, 4 as type, 40 as object, 111 as barcode from dual union all
select '26.03.2015 14:09' as adate, 1 as type, 55 as object, 222 as barcode from dual union all
select '26.03.2015 14:08' as adate, 2 as type, 33 as object, 777 as barcode from dual union all
select '26.03.2015 14:08' as adate, 2 as type, 34 as object, null as barcode from dual union all
select '26.03.2015 13:20' as adate, 3 as type, 41 as object, null as barcode from dual union all
select '26.03.2015 12:00' as adate, 1 as type, 56 as object, 444 as barcode from dual union all
select '26.03.2015 11:59' as adate, 2 as type, 37 as object, 555 as barcode from dual union all
select '26.03.2015 11:59' as adate, 2 as type, 48 as object, null as barcode from dual)
select
adate, type, object, barcode
from sample_data
where type in (1, 2);
type 1 is finished building, type 2 is part of assembly
i need next result
55 | 222 | 26.03.2015 14:08 | 33
55 | 222 | 26.03.2015 14:08 | 34
56 | 444 | 26.03.2015 11:59 | 37
56 | 444 | 26.03.2015 11:59 | 38
so we see what object 55 contain subobject 33, 34 and two date = 26.03.2015 14:08
and object 56 contain subobject 37, 38 and two date = 26.03.2015 11:59
in begin i know two parameters - date and barcode of finished building, for example on my data - date 26.03.2015 14:09 and barcode 222 or date 26.03.2015 12:00 and barcode 444

This query does the job. Subquery T1 connects "types 1" with "types 2". T2 enumerates them using function row_number().
Last query filters only rows with rn = 1.
with t1 as (
select t.*, prior object pob, prior barcode pbc,
prior adate pad, level, sys_connect_by_path(object, '-') pth
from sample_data t where level=2
connect by prior adate > adate and prior type = 1 and type = 2),
t2 as (select t1.*,
row_number() over (partition by object order by pad) rn from t1 )
select pob, pbc, adate, object from t2 where rn = 1
Result:
POB PBC ADATE OBJECT
---------- ---------- ------------------- ----------
55 222 2015-03-26 14:08:00 33
55 222 2015-03-26 14:08:00 34
56 444 2015-03-26 11:59:00 37
56 444 2015-03-26 11:59:00 48

you have to define groups and then you can assign the items to the groups
with sample_data as (select '26.03.2015 14:10' as adate, 4 as type, 40 as object, 111 as barcode from dual union all
select '26.03.2015 14:09' as adate, 1 as type, 55 as object, 222 as barcode from dual union all
select '26.03.2015 14:08' as adate, 2 as type, 33 as object, 777 as barcode from dual union all
select '26.03.2015 14:08' as adate, 2 as type, 34 as object, null as barcode from dual union all
select '26.03.2015 13:20' as adate, 3 as type, 41 as object, null as barcode from dual union all
select '26.03.2015 12:00' as adate, 1 as type, 56 as object, 444 as barcode from dual union all
select '26.03.2015 11:59' as adate, 2 as type, 37 as object, 555 as barcode from dual union all
select '26.03.2015 11:59' as adate, 2 as type, 48 as object, null as barcode from dual),
sd_groups as (select adate, lag(adate, 1) over (order by adate) adate_last, object, barcode from (
select * from sample_data where type = 1
union all select min(adate), null, null, null from sample_data))
select sg.object, sg.barcode, sd.adate, sd.object
from sample_data sd, sd_groups sg
where sd.type = 2 and sd.adate between sg.adate_last and sg.adate;

Related

How can we get multiple rows data as single row in oracle

In image I have given table structure and sample data and I need output result as mentioned
With sample data you provided (lines #1 - 8), this returns desired result. Will it work for all other cases, I have no idea as the question lacks in quite a lot of information so YMMV.
SQL> with employee (id, name, type, visit_date) as
2 (select 1, 'Mohan', '01', date '2010-09-09' from dual union all
3 select 1, 'Mohan', '02', date '2010-09-10' from dual union all
4 --
5 select 1, 'Gani' , '01', date '2010-09-01' from dual union all
6 select 1, 'Gani' , '01', date '2010-09-02' from dual union all
7 select 1, 'Gani' , '01', date '2010-09-03' from dual
8 ),
9 --
10 type1 as
11 (select id, name, visit_date
12 from employee
13 where type = '01'
14 ),
15 type2 as
16 (select id, name, visit_date
17 from employee
18 where type = '02'
19 )
20 select
21 a.id,
22 a.name,
23 a.visit_date type1date,
24 b.visit_date type2date
25 from type1 a left join type2 b on a.id = b.id and a.name = b.name
26 order by a.id, a.name desc, a.visit_date;
ID NAME TYPE1DATE TYPE2DATE
---------- ----- ---------- ----------
1 Mohan 09/09/2010 10/09/2010
1 Gani 01/09/2010
1 Gani 02/09/2010
1 Gani 03/09/2010
SQL>

Oracle- count the number rows based on a condition

I want to create a 'ticket' which counts the number of passes for each ID. When we have a gold pass on any of the ID, this means the pass is applied to all those in booking. So for this example, we want to count 5. For the other pass_codes, we want to simply count the number of passes and exclude those that are nulls. I have an expected output below.
Say I have this data:
Passes
ID | GuestID | Pass_code
----------------------------
100 | 001 | Bronze
100 | 002 | Bronze
101 | 103 | Gold
101 | 104 | NULL
101 | 105 | NULL
101 | 106 | NULL
101 | 107 | NULL
102 | 208 | Silver
103 | 209 | Steel
103 | 210 | Steel
103 | 211 | NULL
Passengers
ID | Passengers
-----------------
100 | 2
101 | 5
102 | 1
103 | 3
I want to count then create a ticket in the output of:
ID 100 | 2 pass (bronze)
ID 101 | 5 pass (because it is gold, we count all passengers)
ID 102 | 1 pass (silver)
ID 103 | 2 pass (steel) (2 passes rather than than 3 as we just want to count only the passes for steel, bronze silver)
I want to do something like this, but as a combined query.
DECLARE #ID = 101; -- i will want to pass in IDs
-- for gold, we want to count all passengers when the gold pass is on
SELECT pp.Passengers
FROM passes
JOIN Passengers pp ON p.ID = pp.ID
WHERE p.pass_code IN'%gold%'
AND PP.id = #id
-- for bronze, silver and steel
SELECT
count(p.ID)
FROM Passes
WHERE p.ID = #id
AND P.pass_code IN ('Bronze', 'silver', 'steel') -- Dont want to check based on NUlls as this may chnage to something else.
)
Any help or advice would be much appreciated.
Does this work for you?
with Passes as (
select 100 as id, 001 as guestid, 'Bronze' as passcode from dual union all
select 100 as id, 002 as guestid, 'Bronze' as passcode from dual union all
select 101 as id, 103 as guestid,'Gold' as passcode from dual union all
select 101 as id, 104 as guestid, NULL as passcode from dual union all
select 101 as id, 105 as guestid, NULL as passcode from dual union all
select 101 as id, 106 as guestid, NULL as passcode from dual union all
select 101 as id, 107 as guestid, NULL as passcode from dual union all
select 102 as id, 208 as guestid, 'Silver' as passcode from dual union all
select 103 as id, 209 as guestid, 'Steel' as passcode from dual union all
select 103 as id, 210 as guestid, 'Steel' as passcode from dual union all
select 103 as id, 211 as guestid, NULL as passcode from dual
)
SELECT
id,passcode,count(ID)
FROM Passes
where passcode is not null and passcode<>'Gold'
group by id,passcode
union all
SELECT
id,'Gold',count(ID)
FROM Passes
where id in
(
select id from Passes where passcode='Gold'
)
group by id
order by id
result:
100 Bronze 2
101 Gold 5
102 Silver 1
103 Steel 2
If I understand your question right the query should be like the following
** The table
create table test (ID number, GuestId number, Pass_code varchar2(10));
insert into test values(100,001,'Bronze');
insert into test values(100,002,'Bronze');
insert into test values(101,103,'Gold');
insert into test values(101,104,NULL);
insert into test values(101,105,NULL);
insert into test values(101,106,NULL);
insert into test values(101,107,NULL);
insert into test values(102,208,'Silver');
insert into test values(103,209,'Steel');
insert into test values(103,210,'Steel');
insert into test values(103,211,NULL);
commit;
SQL> select * from test order by 1,2;
ID GUESTID PASS_CODE
---------- ---------- ------------------------------
100 1 Bronze
100 2 Bronze
101 103 Gold
101 104
101 105
101 106
101 107
102 208 Silver
103 209 Steel
103 210 Steel
103 211
11 rows selected.
** The query
WITH PASSES AS (
SELECT T1.ID,T1.PASS_CODE, COUNT(T2.ID) QUANTITY FROM TEST T1, TEST T2
WHERE T1.PASS_CODE='Gold' AND T1.ID=T2.ID
GROUP BY T1.ID,T1.PASS_CODE
UNION ALL
SELECT ID,PASS_CODE, COUNT(*) QUANTITY FROM TEST
WHERE PASS_CODE IS NOT NULL AND
PASS_CODE != 'Gold'
GROUP BY ID,PASS_CODE)
SELECT ID, QUANTITY || ' (' || PASS_CODE || ')' RESULT FROM PASSES
ORDER BY ID;
** Result
ID RESULT
---------- --------------------
100 2 (Bronze)
101 5 (Gold)
102 1 (Silver)
103 2 (Steel)

How to find text fields that contains a list of words

I'm using Oracle PLSQL.
I want to return TextFields that contains a list of words (with 'and' operator between them).
The result string must contain all the words provided from the user, the order is not importent.
Example:
param_col varchar2(100):= 'Project|Data|Book';
(The list of words are unknown, depend on user parameter)
TextField:
1.'The Project will contain Data from Book'
2.'The Project Data is not valid.
3.'Project is the best data Book exists'
Expected Result:
1.'The Project will contain Data from Book'
3.'Project is the best data Book exists'
Here's one option. See comments within code.
SQL> with
2 test (id, col) as
3 -- Test sample data
4 (select 1, 'The Project will contain Data from Book' from dual union all
5 select 2, 'The Project Data is not valid' from dual union all
6 select 3, 'Project is the best data Book exists' from dual
7 ),
8 param (par) as
9 -- input parameter
10 (select 'Project|Data|Book' from dual),
11 --
12 spltest as
13 -- split TEST sentences to words
14 (select id,
15 lower(regexp_substr(col, '[^ ]+', 1, column_value)) val
16 from test cross join table(cast(multiset(select level from dual
17 connect by level <= regexp_count(col, ' ') + 1
18 ) as sys.odcinumberlist))
19 ),
20 splpar as
21 -- split PARAMETER into words; include IDs from TEST
22 (select t.id,
23 lower(regexp_substr(p.par, '[^\|]+', 1, column_value)) val
24 from param p cross join test t
25 cross join table(cast(multiset(select level from dual
26 connect by level <= regexp_count(p.par, '\|') + 1
27 ) as sys.odcinumberlist))
28 )
29 -- final result: select rows from the TEST table ...
30 select t.id, t.col
31 from test t
32 -- ... where ID is contained in intersected set of values from SPLTEST and SPLPAR ...
33 where t.id in (select x.id from (select t1.id, t1.val from spltest t1
34 intersect
35 select p.id, p.val from splpar p
36 ) x
37 group by x.id
38 -- ... while that "intersected set" has to contain all values from the PARAM
39 having count(*) = (select regexp_count(p1.par, '\|') + 1
40 from param p1
41 )
42 );
ID COL
---------- ---------------------------------------
1 The Project will contain Data from Book
3 Project is the best data Book exists
SQL>

Oracle SQL Developer - How to Display Percents using Color (Not Numbers)

While working out of Oracle SQL Developer I came across a feature that I was unaware of until today. The feature is to display Percentages using colors not unlike how a horizontal bar chart could display the same percentages. I found it by right clicking on the connection and choosing the option 'Manage Database'.
Is this feature available for ANY query/report where percentages are being displayed? The column I'm referring to in the screenshot is the 'Percent_Used' column.
And here’s the code:
SELECT
'SQLDEV:GAUGE:0:20000:1000:5000:' || peeps.salary "WhatIsItYoudSayYouDoHere",
peeps.salary,
peeps.first_name
|| ' '
|| peeps.last_name,
peeps.job_id
FROM
hr.employees peeps;
SQLDEV:GAUGE:0:200:50:150 equates to min:max:low threshold:upper threshold:value to graph
I am providing another example simplifying how to work with basic percents from 0 to 100 without using the Threshold options.
WITH fake_data AS
(
SELECT 20 AS perc, 1001 AS entity FROM dual UNION ALL
SELECT 30 AS perc, 1002 AS entity FROM dual UNION ALL
SELECT 45 AS perc, 1003 AS entity FROM dual UNION ALL
SELECT 100 AS perc, 1004 AS entity FROM dual UNION ALL
SELECT 95 AS perc, 1005 AS entity FROM dual UNION ALL
SELECT 33 AS perc, 1006 AS entity FROM dual UNION ALL
SELECT 57 AS perc, 1007 AS entity FROM dual UNION ALL
SELECT 70 AS perc, 1008 AS entity FROM dual UNION ALL
SELECT 75 AS perc, 1009AS entity FROM dual UNION ALL
SELECT 77 AS perc, 1010 AS entity FROM dual UNION ALL
SELECT 85 AS perc, 1011 AS entity FROM dual UNION ALL
SELECT 90 AS perc, 1012 AS entity FROM dual UNION ALL
SELECT 94 AS perc, 1013 AS entity FROM dual UNION ALL
SELECT 57 AS perc, 1014 AS entity FROM dual UNION ALL
SELECT 60 AS perc, 1015 AS entity FROM dual UNION ALL
SELECT 65 AS perc, 1016 AS entity FROM dual UNION ALL
SELECT 80 AS perc, 1017 AS entity FROM dual
)
, stats AS
( /* Making it easy to adjust the values used by SQLDEV:GAUGE here as a single record. */
SELECT 0 AS min_value, 100 AS max_value, 0 AS low_threshold, 0 AS upper_threshold FROM dual
)
SELECT
'SQLDEV:GAUGE:'|| s.min_value
||':'|| s.max_value
||':'|| s.low_threshold
||':'|| s.upper_threshold
||':'|| fd.perc
AS perc_visual
/* SQLDEV:GAUGE:0:20000:1000:5000 equates to min:max:low threshold:upper threshold:value to graph */
, fd.perc
, fd.entity
FROM stats s, /* Single Record here so we can just use 'comma joins' here aka crappy old skool join syntax */
fake_data fd
ORDER BY perc desc
;

How to get one query about sales set on default date?

I have two tables, T_TEST and T_DEFAULT_DATE. T_TEST contains date and amount, and T_DEFAULT_DATE contains just P_DATE.
First table T_TEST:
DATE AMOUNT
-------- ----------
01.01.99 77
16.02.99 59
01.01.00 12
15.01.00 32
01.02.00 144
15.02.00 320
16.02.00 521
01.03.00 98
15.03.00 76
16.03.00 33
01.01.01 65
15.01.01 78
01.02.01 95
15.02.01 39
16.02.01 97
02.02.02 63
07.03.02 75
And second table T_DEFAULT_DATE:
P_DATE
--------
16.02.01
What I want to get is two queries established in a single query :
1. what is the amount of sale achieved on the same day last year (- 12 mounths)
2. amount of sales for whole past year (based on table T_DEFAULT_DATE)
3. the amount (sum) for whole mounth (default mounth : 1.2. 2001 - 28.2.2001)
Expected output is :
P_SDLY P_LY P_MS
-----------
521 1236 231
I tryed with add_months(t_default_date.p_date, -12) , but I didn't get expected result. Please help
You can try something like this, assuming that your fields are stored in date columns.
SQL> with t_test(date_, amount) as
2 (
3 select to_date('01.01.99', 'dd.mm.rr'), 77 from dual union all
4 select to_date('16.02.99', 'dd.mm.rr'), 59 from dual union all
5 select to_date('01.01.00', 'dd.mm.rr'), 12 from dual union all
6 select to_date('15.01.00', 'dd.mm.rr'), 32 from dual union all
7 select to_date('01.02.00', 'dd.mm.rr'), 144 from dual union all
8 select to_date('15.02.00', 'dd.mm.rr'), 320 from dual union all
9 select to_date('16.02.00', 'dd.mm.rr'), 521 from dual union all
10 select to_date('01.03.00', 'dd.mm.rr'), 98 from dual union all
11 select to_date('15.03.00', 'dd.mm.rr'), 76 from dual union all
12 select to_date('16.03.00', 'dd.mm.rr'), 33 from dual union all
13 select to_date('01.01.01', 'dd.mm.rr'), 65 from dual union all
14 select to_date('15.01.01', 'dd.mm.rr'), 78 from dual union all
15 select to_date('01.02.01', 'dd.mm.rr'), 95 from dual union all
16 select to_date('15.02.01', 'dd.mm.rr'), 39 from dual union all
17 select to_date('16.02.01', 'dd.mm.rr'), 97 from dual union all
18 select to_date('02.02.02', 'dd.mm.rr'), 63 from dual union all
19 select to_date('07.03.02', 'dd.mm.rr'), 75 from dual
20 ),
21 t_default_date(p_date) as
22 (
23 select to_date('16.02.01', 'dd.mm.rr') from dual
24 )
25 select sum(
26 case
27 when date_ between add_months(trunc(p_date, 'yyyy'), -12)
28 and trunc(p_date, 'yyyy')-1
29 then amount
30 else 0
31 end
32 ) as year,
33 sum( decode (date_, add_months(p_date, -12), amount, 0) ) as day,
34 sum( case
35 when date_ between
36 trunc(p_date, 'MM') and
37 last_day(p_date)
38 then amount
39 else
40 0
41 end
42 ) as month
43 from t_test
44 inner join t_default_date on (date_ between add_months(trunc(p_date, 'yyyy'), -12) and last_day(p_date) );
YEAR DAY MONTH
---------- ---------- ----------
1236 521 231
SQL>
This makes use of add_months to get exactly "one year ago"; if you need "365 days ago" (think of leap years), consider using something like date - 365

Resources