Combining column values from different tables - oracle

I stuck. I have 2 tables - look at image no.1 Table columns And i would like to build query, that will give me the result - it is showed on image no 2. the result of query.
I have 2 queries and I would like to mix them up, to obtain the list from image no.2. Please help me, how to build a query.
Query no1: SELECT department_name, department_id FROM DEPARTMENTS WHERE department_id between 90 AND 110;
Query no 2: SELECT last_name, department_id from employees WHERE department_id between 90 AND 110;

Query:
with departments (department_id, department_name) as (
select 90, 'Executive' from dual union all
select 100, 'Finance' from dual union all
select 110, 'Accounting' from dual
),
employees (employee_id, last_name, department_id) as (
select 1003, 'King' , 90 from dual union all
select 1005, 'De Hann' , 90 from dual union all
select 1009, 'Gietz' , 110 from dual union all
select 1013, 'Popp' , 100 from dual union all
select 1014, 'Chen' , 100 from dual union all
select 1015, 'Higgins' , 110 from dual union all
select 1029, 'Greenberg', 100 from dual union all
select 1040, 'Kochar' , 90 from dual union all
select 1043, 'Faviet' , 100 from dual union all
select 1045, 'Urman' , 100 from dual union all
select 1049, 'Sciarra' , 100 from dual
)
-- end input data; begin actual query --
select c_name, department_id from
( select department_name as c_name, department_id, 0 as categ from departments
union all
select ' ' || last_name as c_name, department_id, 1 from employees
order by department_id, categ, c_name
);
Result:
C_NAME DEPARTMENT_ID
------------- -------------
Executive 90
De Hann 90
King 90
Kochar 90
Finance 100
Chen 100
Faviet 100
Greenberg 100
Popp 100
Sciarra 100
Urman 100
Accounting 110
Gietz 110
Higgins 110
You don't need the "with ..." part; just use the query that begins at the SELECT statement after the two factored subqueries (after the "input data"). I even ordered by last name within each department for you; if that is not needed, just delete "c_name" from the ORDER BY clause.
I called the first column c_name; you may call it whatever you want, but calling it department_name when it also holds employee last names didn't make much sense to me. To call it whatever you want, change the SELECT statement from SELECT c_name, department_id to SELECT c_name AS whatever, department_id...

SELECT c.last_name,
d.department_id,
d.department_name
FROM employee c
JOIN deptartment d ON d.department_id=c.department_id
WHERE d.department_id BETWEEN 90 AN 110
OUTPUT from my sample table
+-------+----+------------+
| KING | 10 | ACCOUNTING |
| BLAKE | 30 | SALES |
| CLARK | 10 | ACCOUNTING |
| JONES | 20 | RESEARCH |
| SCOTT | 20 | RESEARCH |
+-------+----+------------+

Related

Oracle query where one column with multiple values must be different

I'm having trouble trying to come up with a query that retrieves COLUMN_A where:
COLUMN_C is having count > 1
And COLUMN_B's values are different.
Table contents
COLUMN_A COLUMN_B COLUMN_C
-------------------------------- ---------------- ---------
000111222 AAAAAAAAA 100
000111222 BBBBBBBBB 100
000111222 CCCCCCCCC 300
000111222 CCCCCCCCC 300
000888999 DDDDDDDDD 300
000888999 DDDDDDDDD 300
777666555 EEEEEEEEE 100
777666555 FFFFFFFFF 100
234567890 GGGGGGGGG 100
234567890 GGGGGGGGG 100
444333111 HHHHHHHHH 100
Expected result
COLUMN_A COLUMN_B COLUMN_C
-------------------------------- ---------------- ---------
000111222 AAAAAAAAA 100
000111222 BBBBBBBBB 100
777666555 EEEEEEEEE 100
777666555 FFFFFFFFF 100
This is where I'm stuck at:
select COLUMN_A, count(*) from SOME_TABLE where COLUMN_C = '100' group by COLUMN having count(*) > '1';
But this query retrieves:
COLUMN_A COLUMN_B COLUMN_C
-------------------------------- ---------------- ---------
000111222 AAAAAAAAA 100
000111222 BBBBBBBBB 100
777666555 EEEEEEEEE 100
777666555 FFFFFFFFF 100
234567890 GGGGGGGGG 100
234567890 GGGGGGGGG 100
I strongly suspect the query lacks a distinct or a count somewhere but, for the life of me, nothing comes to mind.
Any info would be greatly appreciated.
We can try to use two count window functions in the subquery for your grouping logic.
SELECT t1.COLUMN_A ,t1.COLUMN_B ,t1.COLUMN_C
FROM (
select t1.*,
count(*) OVER(PARTITION BY COLUMN_A,COLUMN_B) cnt1,
COUNT(*) OVER(PARTITION BY COLUMN_A,COLUMN_C) cnt2
from SOME_TABLE t1
) t1
WHERE cnt1 = 1 AND cnt2 > 1
sqlfiddle
You can use:
SELECT column_a, column_b, column_c
FROM (
SELECT t.*,
COUNT(column_b) OVER (PARTITION BY column_a, column_c) AS cnt_all,
COUNT(DISTINCT column_b) OVER (PARTITION BY column_a, column_c)
AS cnt_dst
FROM table_name t
)
WHERE cnt_all = cnt_dst
AND cnt_dst > 1
Which, for the sample data:
CREATE TABLE table_name (COLUMN_A, COLUMN_B, COLUMN_C) AS
SELECT '000111222', 'AAAAAAAAA', 100 FROM DUAL UNION ALL
SELECT '000111222', 'BBBBBBBBB', 100 FROM DUAL UNION ALL
SELECT '000111222', 'CCCCCCCCC', 300 FROM DUAL UNION ALL
SELECT '000111222', 'CCCCCCCCC', 300 FROM DUAL UNION ALL
SELECT '000888999', 'DDDDDDDDD', 300 FROM DUAL UNION ALL
SELECT '000888999', 'DDDDDDDDD', 300 FROM DUAL UNION ALL
SELECT '777666555', 'EEEEEEEEE', 100 FROM DUAL UNION ALL
SELECT '777666555', 'FFFFFFFFF', 100 FROM DUAL UNION ALL
SELECT '234567890', 'GGGGGGGGG', 100 FROM DUAL UNION ALL
SELECT '234567890', 'GGGGGGGGG', 100 FROM DUAL UNION ALL
SELECT '444333111', 'HHHHHHHHH', 100 FROM DUAL;
Outputs:
COLUMN_A
COLUMN_B
COLUMN_C
000111222
AAAAAAAAA
100
000111222
BBBBBBBBB
100
777666555
EEEEEEEEE
100
777666555
FFFFFFFFF
100
db<>fiddle here

how to write query to display two rows in one row from same table with different alias column names using oracle

i need to display two rows from same table with different column names. one as Current columns and other as previous columns. How to display it in one row.
SELECT BILL_ID CUR_BILL_ID, BILL_START_DT CUR_BILL_START_DT, BILL_END_DT CUR_BILL_END_DT, BILL_STATUS_CD CUR_BILL_STATUS_CD, BILL_APPROVED_BY CUR_BILL_APPROVED_BY, BILL_APPROVED_DT CUR_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS)
SELECT BILL_ID PRV_BILL_ID, BILL_START_DT PRV_BILL_START_DT, BILL_END_DT PRV_BILL_END_DT, BILL_STATUS_CD PRV_BILL_STATUS_CD, BILL_APPROVED_BY PRV_BILL_APPROVED_BY, BILL_APPROVED_DT PRV_BILL_APPROVED_DT FROM FPM_CB_BILL_DETAILS WHERE BILL_ID = (select max(BILL_ID) from FPM_CB_BILL_DETAILS) - 1
Looks like selfjoin might help.
SQL> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select a.bill_id curr_bill_id,
8 a.bill_status_cd curr_status,
9 b.bill_id prev_bill_id,
10 b.bill_status_cd prev_status
11 from fpm_cb_bill_details a join fpm_cb_bill_details b on b.bill_id = a.bill_id - 1
12 where a.bill_id = (select max(bill_id) from fpm_cb_bill_details);
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
103 status D 102 statuc C
SQL>
You can use lag() analytic function to see the previous row's column values, ordering by bill_id as follows:
FSITJA#db01> with fpm_cb_bill_Details (bill_id, bill_status_cd) as
2 (select 100, 'status A' from dual union all
3 select 101, 'status B' from dual union all
4 select 102, 'statuc C' from dual union all
5 select 103, 'status D' from dual
6 )
7 select d.bill_id curr_bill_id,
8 d.bill_status_cd curr_status,
9 lag(d.bill_id) over (order by d.bill_id) prev_bill_id,
10 lag(d.bill_status_cd) over (order by d.bill_id) prev_status
11 from fpm_cb_bill_Details d;
CURR_BILL_ID CURR_STA PREV_BILL_ID PREV_STA
------------ -------- ------------ --------
100 status A
101 status B 100 status A
102 statuc C 101 status B
103 status D 102 statuc C
Thanks #Littlefoot for the sample table data.

Display the Alternative columns from table row

enter image description here
Display the Alternative columns from table row
Convert the salary column to a string data type (so that salary and name have the same data type) and then UNPIVOT:
Oracle Setup:
CREATE TABLE test_data ( id, name, salary ) AS
SELECT 100, 'A', 1000 FROM DUAL UNION ALL
SELECT 101, 'B', 2000 FROM DUAL UNION ALL
SELECT 102, 'C', 3000 FROM DUAL
Query:
SELECT id, value
FROM (
SELECT id, name, TO_CHAR( salary ) AS salary
FROM test_data
)
UNPIVOT ( value FOR key IN ( name, salary ) )
Output:
ID | VALUE
--: | :----
100 | A
100 | 1000
101 | B
101 | 2000
102 | C
102 | 3000
db<>fiddle here
Alternatively, UNION ALL can also work for you, If you agreed to change the datatype of Salary column -
SELECT ID, Name "Name & Salary"
FROM TABLE1
UNION ALL
SELECT ID, Salary
FROM TABLE1
ORDER BY ID, Name

Find top users who cumulatively have 75% of all points

I am trying to find out the top users who cumulatively have 75% of all points.
Table is:
In this users list must the result should be users (dick, mary, jack and sam).
I try with (Oracle select..)
SELECT o.users, SUM (o.points)
FROM (SELECT users,
SUM (points),
RANK () OVER (ORDER BY SUM (points) DESC) r
FROM points_tbl) o;
--> error is:
ORA-00904: "o"."points": invalid identifier
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE points ( "user", points ) AS
SELECT 'joe', 10 FROM DUAL UNION ALL
SELECT 'bill', 15 FROM DUAL UNION ALL
SELECT 'dick', 25 FROM DUAL UNION ALL
SELECT 'jack', 32 FROM DUAL UNION ALL
SELECT 'mary', 45 FROM DUAL UNION ALL
SELECT 'noe', 12 FROM DUAL UNION ALL
SELECT 'sam', 18 FROM DUAL;
Query 1:
SELECT "user", points
FROM (
SELECT p.*,
COALESCE(
SUM( points ) OVER (
ORDER BY points DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
),
0
) / SUM( points ) OVER () AS pct
FROM points p
ORDER BY points DESC
)
WHERE pct < .75
Results:
| user | POINTS |
|------|--------|
| mary | 45 |
| jack | 32 |
| dick | 25 |
| sam | 18 |

Oracle Stored Procedure - Number of heat waves (number of pattern matches in a series)

I need to postprocess a Oracle dataset in order to find the number of heat waves.
By definition, a heat waves occurs when the data value is greater than a threshold at least two consecutive times.
For example, given the threshold=20 and the sequence
23 31 32 17 16 23 16 21 22 18
the heat waves are 2:
{23,31,32} and {21,22}
and the lenght of the longest one is 3 (size of bigger subset)
My input dataset consists of several sequences; a sample input result set is:
-----------------------------
| ID | DAY | VALUE |
-----------------------------
| 100 | 1/1/17 | 20 |
| 100 | 2/1/17 | 21 |
| 200 | 1/1/17 | 12 |
| 200 | 2/1/17 | 24 |
| ... ... ...
In other words, I have a sequence per each ID and I need to output something like that:
-----------------------
| ID | #heat waves |
-----------------------
| 100 | 3 |
| 200 | 1 |
Here the current version of my stored procedure:
create or replace PROCEDURE sp (
p_query IN VARCHAR2,
cursor_ out sys_refcursor
) AS
processed processed_data_table := processed_data_table();
c sys_refcursor;
BEGIN
OPEN c FOR p_query;
processed.EXTEND;
processed(processed.count) := processed_data_obj();
fetch c INTO processed(processed.count).ID,
processed(processed.count).DAY, processed(processed.count).VALUE;
while c%found
processed.EXTEND;
processed(processed.count) := processed_data_obj();
fetch c INTO processed(processed.count).ID,
processed(processed.count).DAY, processed(processed.count).VALUE;
END loop;
CLOSE c;
processed.TRIM;
// HERE I NEED TO PROCESS processed TABLE AND STORE RESULT IN output
TABLE
OPEN cursor_ FOR
SELECT *
FROM TABLE( output);
END sp;
Anyone could help me providing a solution?
Thanks
In Oracle 12c, use MATCH_RECOGNIZE:
select id, count(*) "# of heatwaves" from series_data
match_recognize ( partition by id
order by day
one row per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
UPDATE: Also show longest heat wave for each series
To get the longest heatwave in each series, we have to introduce a MEASURES clause to the MATCH_RECOGNIZE, as below:
select id,
max(heatwave_length) "longest heatwave",
count(distinct heatwave_number) "# of heatwaves"
from series_data
match_recognize ( partition by id
order by day
measures
FINAL COUNT(*) as heatwave_length,
MATCH_NUMBER() heatwave_number
all rows per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
order by id;
Full example with data:
with series_data ( id, day, value ) as
( SELECT 100, date '2017-01-01', 23 from dual union all
SELECT 100, date '2017-01-02', 31 from dual union all
SELECT 100, date '2017-01-03', 32 from dual union all
SELECT 100, date '2017-01-04', 44 from dual union all
SELECT 100, date '2017-01-05', 16 from dual union all
SELECT 100, date '2017-01-06', 23 from dual union all
SELECT 100, date '2017-01-07', 16 from dual union all
SELECT 100, date '2017-01-08', 21 from dual union all
SELECT 100, date '2017-01-09', 22 from dual union all
SELECT 100, date '2017-01-10', 18 from dual union all
SELECT 200, date '2017-01-01', 23 from dual union all
SELECT 200, date '2017-01-02', 31 from dual union all
SELECT 200, date '2017-01-03', 32 from dual union all
SELECT 200, date '2017-01-04', 17 from dual union all
SELECT 200, date '2017-01-05', 16 from dual union all
SELECT 200, date '2017-01-06', 23 from dual union all
SELECT 200, date '2017-01-07', 16 from dual union all
SELECT 200, date '2017-01-08', 21 from dual union all
SELECT 200, date '2017-01-09', 22 from dual union all
SELECT 200, date '2017-01-10', 22 from dual union all
SELECT 200, date '2017-01-11', 6 from dual union all
SELECT 200, date '2017-01-12', 22 from dual union all
SELECT 200, date '2017-01-13', 22 from dual )
select id,
max(heatwave_length) "longest heatwave",
count(distinct heatwave_number) "# of heatwaves"
from series_data
match_recognize ( partition by id
order by day
measures
FINAL COUNT(*) as heatwave_length,
MATCH_NUMBER() heatwave_number
all rows per match
after match skip past last row
pattern ( over_threshold{2,} )
define
over_threshold as value > 20 )
group by id
order by id;
Results:
ID longest heatwave # of heatwaves
----- -------------- --------------
100 4 2
200 3 3

Resources