Oracle - Look up for the data in pivoted table - oracle

I have a table which has columns as follows:
USERID, USERTYPE, DIVISION, SUBDIVISION
For each userid, there will be one or more usertypes (e.g. a user can be a developer or administrator or both). Depending on the usertype a user can be subscribed to the divisions and optionally its subdivisions.
USERID, USERTYPE and DIVISION are not null columns.
The output is required in the following format -
USERID, USERTYPE, DIVISION1, DIVISION2, DIVISION3 .. and so on
So, there should be a unique record for a combination of USERID-USERTYPE.
For this I have used PIVOT operator which works fine. I have also created a temporary table (let's say Table1) to store this result of this query.
Now, if a user is subscribed to subdivisions, the values of subdivisions should be written under that division as comma separated values. If it is not subscribed to subdivisions, simple divisions will appear under its respective column.
I have written a query using LISTAGG function which gives me comma separated subdivisions for each USERID-USERTYPE combination. The result of this query is stored in Table2.
Now when I join the tables Table1 and Table2 on USERID and USERTYPE, I get multiple rows for a single USERID-USERTYPE combination, which is obvious but not what is needed.
Here is some sample data:
Please note the records for USERID = 3.
What I am getting is in "Result of join query" and what I need is in "Final Result".
Also, I cannot use LISTAGG before the pivot query, because later on while building the pivot query it will be too tedious to list all the possible combinations of subdivisions.
I am sure I am missing some small point here, but cannot figure out what.
Any suggestions or pointers will be of great help.
Thanks in advance.

There are no need to list all subdivisions in pivot query, just aggregate it within a groups of unique combinations of USERID, USERTYPE, DIVISION and use nvl(AGGREGATED_VALUE,DIVISION) to get a value for filling pivot table.
If source_table is a table with USERID, USERTYPE, DIVISION, SUBDIVISION columns which you mentioned first in your question, then this example must work for you:
select * from (
select
userid,
usertype,
division,
-- get prepared value for pivot
nvl(
listagg(subdivision, ',') within group (order by subdivision),
division
) subdiv_list
from
source_table
group by
userid, usertype, division
)
pivot (
max(subdiv_list) for division in ('Div1', 'Div2')
)
SQLFidlle
P.S. Just as a side story, generation of a list of columns dynamically may be useful. Check this SO article.

Related

Spring JPA: Need to join two table with dynamic clauses

Requirement is as below:
Table 1 - Order(ID, orderId, sequence, reference, valueDate, date)
Table 2 - Audit(AuditId, orderId, sequence, status, updatedBy, lastUpdatedDateTime)
For each record in ORDER table, there could be one or many rows in AUDIT table.
User is given a search form where he could enter any of the search params including status from audit table.
I need a way to join these two tables with dynamic where clause and get the top row for a given ORDER from AUDIT table.
Something like below:
select * from
ORDER t1, AUDIT t2
where t1.orderid = t2.orderId
and t1.sequence = t2.sequence
and t2.status = <userProvidedStatusIfAny>
and t2.lastUpdatedDateTime in (select max(t3.lastUpdatedDateTime) --getting latest record
AUDIT t3 where t1.orderid = t3.orderId
and t1.sequence = t3.sequence)
and t1.valudeDate = <userProvidedDataIfAny> ..... so on
Please help
-I cant do this with #Query because i have to form dynamic where clause
-#OneToMany fetches all the records in audit table for given orderId and sequence
-#Formula in ORDER table works but for only one column in select. i need multiple values from AUDIT table
Please help

find a best way to traverse oracle table

I have an oracle table. Table's DDL is (not have the primary key)
create table CLIENT_ACCOUNT
(
CLIENT_ID VARCHAR2(18) default ' ' not null,
ACCOUNT_ID VARCHAR2(18) default ' ' not null,
......
)
create unique index UK_ACCOUNT
on CLIENT_ACCOUNT (CLIENT_ID, ACCOUNT_ID)
Then, the data's scale is very huge, maybe 100M records. I want to traverse this whole table's data with batch.
Now, I use the table's index to batch traverse. But I have some oracle grammar problems.
# I want to use this SQL, but grammar error.
# try to use b-tree's index to locate start position, but not work
select * from CLIENT_ACCOUNT
WHERE (CLIENT_ID, ACCOUNT_ID) > (1,2)
AND ROWNUM < 1000
ORDER BY CLIENT_ID, ACCOUNT_ID
Has the fastest way to batch touch table data?
Wild guess:
select * from CLIENT_ACCOUNT
WHERE CLIENT_ID > '1'
and ACCOUNT_ID > '2'
AND ROWNUM < 1000;
It would at least compile, although whether it correctly implements your business logic is a different matter. Note that I have cast your filter criteria to strings. This is because your columns have a string datatype and you are defaulting them to spaces, so there's a high probability those columns contain non-numeric values.
If this doesn't solve your problem, please edit your question with more details; sample input data and expected output is always helpful in these situations.
Your data model seems odd.
Your columns are defined as varchar2. So why is your criteria numeric?
Also, why do you default the key columns to space? It would be better to leave unpopulated values as null. (To be clear, NULL is not a good thing in an indexed column, it's just better than a space.)

Oracle APEX return multiple values in LoV

I have a field as PopUp LOV and as source a shared component with the corresponding code.
`SELECT u.Lastname || ', ' || u.Firstname AS displayed, i.IUUID
from INTERNAL_SUPERVISORS i
left outer join USERS u on i.UUID=u.UUID
union
SELECT u2.Lastname || ', ' || u2.Firstname AS displayed, p.PRID
FROM PROFESSOR p
left outer join USERS u2 on p.UUID=u2.UUID `
This is my column mapping in the LoV:
I want it to be possible to select a person from the one or from another table and give different IDs as return value depending on the selection.
With this implementation it is possible to see and select persons from both tables but when I save the form, I cannot see the User from the professor table but can only see the person from the other table.
Is it because of the return value in the column mapping?
If so is it possible to select two possible return values?
I cannot see the User from the professor table
I'd say that it depends on how you're looking at it. If data in a table (you use to store values selected from that LoV) corresponds to two tables, then - when reviewing data - you have to join it to both other tables - internal_supervisors and professor.
Usually, when designing data model, we use foreign keys to maintain referential integrity. As you allow both iuuid and prid to be stored, then it means that you have to check both of those tables while retrieving data.

Oracle order by varchar2 with numeric values in it

I have an issue where a Oracle DB column(say 'REF_NO') is VARCHAR2 and carries values similar to the ones below
If I do an ORDER BY REF_NO I get this:
LET-2-1
LET-2-10
LET-2-11
LET-2-2
LET-2-3
Which makes sense because the values are being treated as characters. I have been asked to change this so that the returned results are ordered like this:
LET-2-1
LET-2-2
LET-2-3
LET-2-10
LET-2-11
I cannot guarantee the format of these values either so I cannot really see how I can use regex or sub-string as it's a completely free text entry for users to enter values. The example above just happens to be what the requested data looks like. Other data could be completely different.
I cannot see how this is possible, so was hoping for some suggestions.
Additional information
To add to the complexity, here are some more examples from other customers:
Customer 1: OB 12, WE-11, WAN-001
Customer 2: P4, D1, W9
Customer 3: NTT-33A, RLC-33L, ARR-129B
Here are the steps
create table test01 (c varchar2(30));
insert into test01 values ('LET-2-1');
insert into test01 values ('LET-2-10');
insert into test01 values ('LET-2-2');
Query
select * from test01
order by to_number(SUBSTR(C,INSTR(C,'-',1)+1,INSTR(C,'-',1,2)-INSTR(C,'-',1)-1)),
to_number(SUBSTR(C,INSTR(C,'-',-1)+1));
Assuming all the values are having structure of -- - in the above query I try to extract numbers and converted to number in order by clause.
select * from TABLE
ORDER BY LENGTH(REF_NO), REF_NO
first you need to order by length and then order by REF_NO

optimize query with minus oracle

Wanted to optimize a query with the minus that it takes too much time ... if they can give thanked help.
I have two tables A and B,
Table A: ID, value
Table B: ID
I want all of Table A records that are not in Table B. Showing the value.
For it was something like:
Select ID, value
FROM A
WHERE value> 70
MINUS
Select ID
FROM B;
Only this query is taking too long ... any tips how best this simple query?
Thank you for attention
Are ID and Value indexed?
The performance of Minus and Not Exists depend:
It really depends on a bunch of factors.
A MINUS will do a full table scan on both tables unless there is some
criteria in the where clause of both queries that allows an index
range scan. A MINUS also requires that both queries have the same
number of columns, and that each column has the same data type as the
corresponding column in the other query (or one convertible to the
same type). A MINUS will return all rows from the first query where
there is not an exact match column for column with the second query. A
MINUS also requires an implicit sort of both queries
NOT EXISTS will read the sub-query once for each row in the outer
query. If the correlation field (you are running a correlated
sub-query?) is an indexed field, then only an index scan is done.
The choice of which construct to use depends on the type of data you
want to return, and also the relative sizes of the two tables/queries.
If the outer table is small relative to the inner one, and the inner
table is indexed (preferrable a unique index but not required) on the
correlation field, then NOT EXISTS will probably be faster since the
index lookup will be pretty fast, and only executed a relatively few
times. If both tables a roughly the same size, then MINUS might be
faster, particularly if you can live with only seeing fields that you
are comparing on.
Minus operator versus 'not exists' for faster SQL query - Oracle Community Forums
You could use NOT EXISTS like so:
SELECT a.ID, a.Value
From a
where a.value > 70
and not exists(
Select b.ID
From B
Where b.ID = a.ID)
EDIT: I've produced some dummy data and two datasets for testing to prove the performance increases of indexing. Note: I did this in MySQL since I don't have Oracle on my Macbook.
Table A has 2600 records with 2 columns: ID, val.
ID is an autoincrement integer
Val varchar(255)
Table b has one column, but more records than Table A. Autoincrement (in gaps of 3)
You can reproduce this if you wish: Pastebin - SQL Dummy Data
Here is the query I will be using:
select a.id, a.val from tablea a
where length(a.val) > 3
and not exists(
select b.id from tableb b where b.id = a.id
);
Without Indexes, the runtime is 986ms with 1685 rows.
Now we add the indexes:
ALTER TABLE `tablea` ADD INDEX `id` (`id`);
ALTER TABLE `tableb` ADD INDEX `id` (`id`);
With Indexes, the runtime is 14ms with 1685 rows. That's 1.42% the time it took without indexes!

Resources