filter multiple lines based on one value - business-intelligence

in my BO
I have a table with:
OrderID | order Number | reason code
123 | a | r2
123 | b | r1
123 | c | r3
124 |d | r3
I'm using same source for 2 sheets and on one I need all OrderID's where i Have reason R2 for at least one line
and on another all the rest
so need to one should have only:
OrderID | order Number | reason code
123 | a | r2
123 | b | r1
123 | c | r3
and second sheet should only have:
OrderID | order Number | reason code
124 |d | r3
I can add that order numbers are unique so cant have 2 of the same numbers in different orders... if it makes any difference.??

Something like this?
1st sheet -
;with test_data(order_id, order_number, reason_code) as (
select 123, 'a', 'r2' union all
select 123, 'b', 'r1' union all
select 123, 'c', 'r3' union all
select 124, 'd', 'r3'
)
--
-- Test data above; Desired query below
--
select *
from test_data a
where exists (
select 1 from test_data b
where a.order_id = b.order_id
and b.reason_code = 'r2'
)
Output:
123 a r2
123 b r1
123 c r3
2nd sheet -
;with test_data(order_id, order_number, reason_code) as (
select 123, 'a', 'r2' union all
select 123, 'b', 'r1' union all
select 123, 'c', 'r3' union all
select 124, 'd', 'r3'
)
--
-- Test data above; Desired query below
--
select *
from test_data a
where NOT exists (
select 1 from test_data b
where a.order_id = b.order_id
and b.reason_code = 'r2'
)
Output:
124 d r3
Hope this helps. Please revert.

Related

How to use Oracle's LISTAGG function with a multi values?

I have an 'ITEMS' table like below:
ITEM_NO ITEM_NAME
1 Book
2 Pen
3 Sticky Notes
4 Ink
5 Corrector
6 Ruler
In another 'EMP_ITEMS' table I have the below:
EMPLOYEE ITEMS_LIST
John 1,2
Mikel 5
Sophia 2,3,6
William 3,4
Daniel null
Michael 6
The output has to be like this:
EMPLOYEE ITEMS_LIST ITEM_NAME
John 1,2 Book,Pen
Mikel 5 Corrector
Sophia 2,3,6 Pen,Sticky Notes,Ruler
William 3,4 Sticky Notes,Ink
Daniel null null
Michael 6 Ruler
I used the below query:
SELECT e.EMPLOYEE,e.ITEMS_LIST, LISTAGG(i.ITEM_NAME, ',') WITHIN GROUP (ORDER BY i.ITEM_NAME) ITEM_DESC
FROM EMP_ITEMS e
INNER JOIN ITEMS i ON i.ITEM_NO = e.ITEMS_LIST
GROUP BY e.EMPLOYEE,e.ITEMS_LIST;
But there is an error:
ORA-01722: invalid number
But there is an error: ORA-01722: invalid number
That is because your ITEMS_LIST is a string composed of numeric and comma characters and is not actually a list of numbers and you are trying to compare a single item number to a list of items.
Instead treat it as a string a look for sub-string matches. To do this you will need to surround the strings in the delimiter character and compare to see if one is the substring of the other:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE Items ( ITEM_NO, ITEM_NAME ) As
SELECT 1, 'Book' FROM DUAL UNION ALL
SELECT 2, 'Pen' FROM DUAL UNION ALL
SELECT 3, 'Sticky Notes' FROM DUAL UNION ALL
SELECT 4, 'Ink' FROM DUAL UNION ALL
SELECT 5, 'Corrector' FROM DUAL UNION ALL
SELECT 6, 'Ruler' FROM DUAL;
CREATE TABLE emp_items ( EMPLOYEE, ITEMS_LIST ) AS
SELECT 'John', '1,2' FROM DUAL UNION ALL
SELECT 'Mikel', '5' FROM DUAL UNION ALL
SELECT 'Sophia', '3,2,6' FROM DUAL UNION ALL
SELECT 'William', '3,4' FROM DUAL UNION ALL
SELECT 'Daniel', null FROM DUAL UNION ALL
SELECT 'Michael', '6' FROM DUAL;
Query 1:
SELECT e.employee,
e.items_list,
LISTAGG( i.item_name, ',' )
WITHIN GROUP (
ORDER BY INSTR( ','||e.items_list||',', ','||i.item_no||',' )
) AS item_names
FROM emp_items e
LEFT OUTER JOIN
items i
ON ( ','||e.items_list||',' LIKE '%,'||i.item_no||',%' )
GROUP BY e.employee, e.items_list
Results:
| EMPLOYEE | ITEMS_LIST | ITEM_NAMES |
|----------|------------|------------------------|
| John | 1,2 | Book,Pen |
| Mikel | 5 | Corrector |
| Daniel | (null) | (null) |
| Sophia | 3,2,6 | Sticky Notes,Pen,Ruler |
| Michael | 6 | Ruler |
| William | 3,4 | Sticky Notes,Ink |

Selecting only distinct record from table in oracle

I have table with following records;
ID | NN | MBL | IC | OTHER
---+-----+------+----+------
1 | 123 | | | ac
2 | | 544 | | dc
3 | | | 524| df
4 |527 | | 124| ff
5 |123 | | | tr // duplicate NN of ID 1
6 | | 544 | | op // duplicate MBL of ID 2
7 | | | 124| ii // duplicate for IC ID 4
When querying with select I need just records with single entry, skipping second occurrence,
select
ID, NN, MBL, IC, OTHER
from
TABLE1 // this should return only one entry of any NN, MBL and IC
How do I get this, I cannot use distinct for multiple columns and I also need ID and OTHER column to display in select query
Expecting result like this:
1 | 123 | | | ac
2 | | 544 | | dc
3 | | | 524| df
4 |527 | | 124| ff
You can use the analytical function ROW_NUMBER() to calculate ranks over each column you want and filter only these rows with rank = 1.
Here is an example:
WITH testdata AS (
SELECT 1 AS ID, 123 AS NN, NULL AS MBL, NULL AS IC, 'ac' AS OTHER FROM DUAL UNION ALL
SELECT 2, NULL, 544 , NULL, 'dc' FROM DUAL UNION ALL
SELECT 3, NULL, NULL, 524 , 'df' FROM DUAL UNION ALL
SELECT 4, 527, NULL, 124, 'ff' FROM DUAL UNION ALL
SELECT 5, 123, NULL, NULL, 'tr' FROM DUAL UNION ALL
SELECT 6, NULL, 544, NULL, 'op' FROM DUAL UNION ALL
SELECT 7, NULL, NULL , 124, 'ii' FROM DUAL
)
SELECT *
FROM(SELECT ID,
NN,
CASE WHEN NN IS NULL THEN 1 ELSE ROW_NUMBER() OVER (PARTITION BY NN ORDER BY ID) END AS NN_RANG,
MBL,
CASE WHEN MBL IS NULL THEN 1 ELSE ROW_NUMBER() OVER (PARTITION BY MBL ORDER BY ID) END AS MBL_RANG,
IC,
CASE WHEN IC IS NULL THEN 1 ELSE ROW_NUMBER() OVER (PARTITION BY IC ORDER BY ID) END AS IC_RANG,
OTHER
FROM testdata
)
WHERE NN_RANG = 1
AND MBL_RANG = 1
AND IC_RANG = 1
;
Hope it helps.

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 |

Delete Oracle with join tables

I have a table that has three columns ( primary key) and I need a delete sentece that allows me to remove the elements I don't need , using a join with the this table and other table, I've tried two delete sentences but they are not working as expected:
First One: This one gets the values I dont need and they are removed from table A, but the issue here is it deletes the values from Table B and C too and those rows can't be removed
DELETE
FROM
(SELECT A.*
FROM TABLE_A A
JOIN TABLE_B B
ON A.CODE =B.CODE
JOIN TABLE_C C
ON B.PRODUCT =C.PRODUCT
WHERE B.VALUE >10000
AND C.RANGE NOT IN (4006, 4005, 4004, 4003, 4002, 4001)
);
**Second One:**The problem with this one is that it removes all the rows from table A, but if I test the query ( select) it returns 5 rows, the ones that should be removed.
DELETE
FROM A WHERE EXIST
(SELECT A.*
FROM TABLE_A A
JOIN TABLE_B B
ON A.CODE =B.CODE
JOIN TABLE_C C
ON B.PRODUCT =C.PRODUCT
WHERE B.VALUE >10000
AND C.RANGE NOT IN (4006, 4005, 4004, 4003, 4002, 4001)
);
So has anyone any idea of what I could be doing wrong?
The first one will delete matched rows across the joins, the second one will delete all rows when there EXISTS any one matched row as you are not correlating the deleted rows to the sub-query.
You can perform this correlation using the ROWID pseudo-column:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_a ( id, code ) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 2 FROM DUAL UNION ALL
SELECT 3, 3 FROM DUAL;
CREATE TABLE table_b ( id, code, product, value ) AS
SELECT 1, 1, 1, 10001 FROM DUAL UNION ALL
SELECT 2, 2, 2, 10001 FROM DUAL UNION ALL
SELECT 3, 3, 1, 9999 FROM DUAL;
CREATE TABLE table_c ( id, product, range ) AS
SELECT 1, 1, 1001 FROM DUAL UNION ALL
SELECT 2, 2, 4001 FROM DUAL;
DELETE
FROM table_A
WHERE ROWID IN (
SELECT A.ROWID
FROM TABLE_A A
JOIN TABLE_B B
ON A.CODE = B.CODE
JOIN TABLE_C C
ON B.PRODUCT = C.PRODUCT
WHERE B.VALUE >10000
AND C.RANGE NOT IN (4006, 4005, 4004, 4003, 4002, 4001)
);
Query 1:
SELECT * FROM table_a
Results:
| ID | CODE |
|----|------|
| 2 | 2 |
| 3 | 3 |
Query 2:
SELECT * FROM table_b
Results:
| ID | CODE | PRODUCT | VALUE |
|----|------|---------|-------|
| 1 | 1 | 1 | 10001 |
| 2 | 2 | 2 | 10001 |
| 3 | 3 | 1 | 9999 |
Query 3:
SELECT * FROM table_c
Results:
| ID | PRODUCT | RANGE |
|----|---------|-------|
| 1 | 1 | 1001 |
| 2 | 2 | 4001 |

Merging Query Result into single row - Oracle

Can I do like this in oracle,.? I have some data like this:
No | Data |
===========
1 | A |
1 | B |
1 | C |
1 | D |
Is there any query that can produce a result like this,.?
No | Data |
=================
1 | A, B, C, D |
Many thanks :D
Maybe this page shows what you are looking for.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TEST ( ID, DATA ) AS
SELECT 1, 'A' FROM DUAL
UNION ALL SELECT 1, 'B' FROM DUAL
UNION ALL SELECT 1, 'C' FROM DUAL
UNION ALL SELECT 1, 'D' FROM DUAL
UNION ALL SELECT 2, 'E' FROM DUAL
UNION ALL SELECT 2, 'F' FROM DUAL;
Query 1:
SELECT ID,
LISTAGG( DATA, ',' ) WITHIN GROUP ( ORDER BY DATA ) AS AGGREGATED_DATA
FROM TEST
GROUP BY ID
Results:
| ID | AGGREGATED_DATA |
|----|-----------------|
| 1 | A,B,C,D |
| 2 | E,F |
In Oracle we can use wm_concat function. Here is the query for example above:
SELECT no, wm_concat(data) from table group by no
reference: wm_concat
select
no,
rtrim (xmlagg (xmlelement (d, data|| ',')).extract ('//text()'), ',') data
from
table_name
group by
no
;

Resources