How to use apex-d3-organization-chart plugin - oracle

I want to create an organization chart with apex-d3-organization-chart plugin.
I added this plugin, then I created a page and inserted a region and changed that to this plugin.
In the source section of that region has written this code:
SELECT
/* positive number id of the element (should start with 1 or higher) */
ROWNUM AS ID,
/* positive number id of the parent (top parent should be 0) */
CASE
WHEN ROWNUM <= 1 THEN 0
WHEN ROWNUM <= 4 THEN 1
ELSE ROUND(ROWNUM / 4)
END AS PARENT_ID,
/* name of the item */
'Item '
|| ROWNUM AS NAME,
/* tooltip for the item */
'This is item '
|| ROWNUM AS TOOLTIP,
/* link of the item (is only used when is leaf) */
'https://github.com/RonnyWeiss' AS LINK,
/* color of the item */
DECODE(ROWNUM, 1, 'rgba(192,0,15,1)', NULL) AS COLOR
FROM DUAL
CONNECT BY ROWNUM <= 30
Now I want to change that and use my table.
How can I do that?

First copy that query in SQL command and run that. Now you can see a table with some fields. Now write a select query that has fields exactly like the source query.
Something like that:
SELECT
ID,
PARENT_ID,
TITLE as NAME,
CASE WHEN
PARENT_ID=0 THEN 'rgba(192,0,15,1)'
ELSE 'rgba(0,0,250,1)'
END as COLOR
FROM TLX_USER_ROLE
ORDER BY PARENT_ID asc

Related

How to copy data along a dimension while avoiding unique name constraint issues in Oracle

Database is Oracle 18c
Data info:
We have the temporal notion of Seasons, and we have a set of Business Groups in each Season. My table, AGROUP, has columns(ID*[auto-generated], NAME, SEASON_ID). Group Names must be unique by Season. Said another way, I can have two groups with the same name ONLY if they are in different seasons.
Task At Hand:
I need to create a stored procedure that, given a source season and a target season, can copy all the groups from the source season to the target season. This part is easy enough. The naive solution is:
PROCEDURE COPY_GROUPS(IN_SOURCE_SEASON_ID IN SEASON.ID%TYPE,
IN_TARGET_SEASON_ID IN SEASON.ID%TYPE)
AS
WITH SOURCE AS
(SELECT AG.ID AS AG_ID,
AG.NAME,
AG.SEASON_ID
FROM AGROUP AG
WHERE AG.SEASON_ID = IN_SOURCE_SEASON_ID)
INSERT INTO AGROUP (NAME, SEASON_ID)
SELECT SRC.NAME,
IN_TARGET_SEASON_ID AS SEASON_ID,
FROM SOURCE SRC;
COMMIT;
END;
The tricky bit is that it is possible that there exists a group in the target season that already has the same name as a group in the source season. Without intervention, this would generate a unique constraint error. In this case, we want to copy the group but re-name it to something unique. Any method to rename is fine, but my first thought is simply to rename with a suffixed number. To do this, I suppose I would change things around to open a REFCURSOR and loop through, inserting one at a time and catching the unique constraint error and responding with a re-attempt to insert with a number suffixed. I'm really in-experienced with routing error handling like this in Oracle however. I could really use some pointing in the right direction.
Thanks for the help!
I played around with this a bit. I'd say to try to do the conditional logic in a case statement as per the following example. You'll need a better way to generate sequences though.
/* INSERT INTO AGROUP (id, NAME, SEASON_ID) */
WITH agroup as
(
select 1 id, 'A' name, 1 season_id from dual union
select 2 id, 'A' name, 2 season_id from dual union
select 3 id, 'B' name, 1 season_id from dual union
select 4 id, 'C' name, 2 season_ud from dual
)
, SOURCE AS
(SELECT rownum row_num, AG.ID AS AG_ID,
AG.NAME,
AG.SEASON_ID
FROM AGROUP AG
WHERE AG.SEASON_ID = 1 /* source season */
)
SELECT /* sequence generation */ (select max(id) from agroup) + row_num as id
, case when SRC.NAME in (select name
from agroup
where agroup.season_id = 2 /* target season */
and agroup.name = src.name
)
then src.name || ' ' || to_char(sysdate, 'DD-MON-YYYY hh24:MI:SS')
else src.name
end as name
, 2 /* target season */ AS SEASON_ID
FROM SOURCE SRC
;

ORACLE apex - looping through checkbox items using PL/SQL

I have a checkbox on my page P3_Checkbox1 that is populated from the database. How can I loop through all the checked values of my checkbox in PL/SQL code?
I assume that APEX_APPLICATION.G_F01 is used only by sql generated checkboxes and I cannot use it for regular checbox as it would not populate G_Fxx array.
I think I understand now what you're saying.
For example, suppose that the P3_CHECKBOX1 checkbox item allows 3 values (display/return):
Absent: -1
Unknown: 0
Here: 1
I created a button (which will just SUBMIT the page) and two text items which will display checked values: P3_CHECKED_VALUES and P3_CHECKED_VALUES_2.
Then I created a process which fires when the button is pressed. The process looks like this (read the comments as well, please):
begin
-- This is trivial; checked (selected) values are separated by a colon sign,
-- just like in a Shuttle item
:P3_CHECKED_VALUES := :P3_CHECKBOX1;
-- This is what you might be looking for; it uses the APEX_STRING.SPLIT function
-- which splits selected values (the result is ROWS, not a column), and these
-- values can then be used in a join or anywhere else, as if it was result of a
-- subquery. The TABLE function is used as well.
-- LISTAGG is used just to return a single value so that I wouldn't have to worry
-- about TOO-MANY-ROWS error.
with
description (code, descr) as
(select -1, 'Absent' from dual union all
select 0 , 'Unknown' from dual union all
select 1 , 'Here' from dual),
desc_join as
(select d.descr
from description d join (select * from table(apex_string.split(:P3_CHECKED_VALUES, ':'))) s
on d.code = s.column_value
)
select listagg(j.descr, ' / ') within group (order by null)
into :P3_CHECKED_VALUES_2
from desc_join j;
end;
Suppose that the Absent and Unknown values have been checked. The result of that PL/SQL process is:
P3_CHECKED_VALUES = -1:0
P3_CHECKED_VALUES_2 = Absent / Unknown
You can rewrite it as you want; this is just one example.
Keywords:
APEX_STRING.SPLIT
TABLE function
I hope it'll help.
[EDIT: loop through selected values]
Looping through those values isn't difficult; you'd do it as follows (see the cursor FOR loop):
declare
l_dummy number;
begin
for cur_r in (select * From table(apex_string.split(:P3_CHECKED_VALUES, ':')))
loop
select max(1)
into l_dummy
from some_table where some_column = cur_r.column_value;
if l_dummy is null then
-- checked value does not exist
insert into some_table (some_column, ...) valued (cur_r.column_value, ...);
else
-- checked value exists
delete from some_table where ...
end if;
end loop;
end;
However, I'm not sure what you meant by saying that a "particular combination is in the database". Does it mean that you are storing colon-separated values into a column in that table? If so, the above code won't work either because you'd compare, for example
-1 to 0:-1 and then
0 to 0:-1
which won't be true (except in the simplest cases, when checked and stored values have only one value).
Although Apex' "multiple choices" look nice, they can become a nightmare when you have to actually do something with them (like in your case).
Maybe you should first sort checkbox values, sort database values, and then compare those two strings.
It means that LISTAGG might once again become handy, such as
listagg(j.descr, ' / ') within group (order by j.descr)
Database values could be sorted this way:
SQL> with test (col) as
2 (select '1:0' from dual union all
3 select '1:-1:0' from dual
4 ),
5 inter as
6 (select col,
7 regexp_substr(col, '[^:]+', 1, column_value) token
8 from test,
9 table(cast(multiset(select level from dual
10 connect by level <= regexp_count(col, ':') + 1
11 ) as sys.odcinumberlist))
12 )
13 select
14 col source_value,
15 listagg(token, ':') within group (order by token) sorted_value
16 from inter
17 group by col;
SOURCE SORTED_VALUE
------ --------------------
1:-1:0 -1:0:1
1:0 0:1
SQL>
Once you have them both sorted, you can compare them and either INSERT or DELETE a row.

Trying to create a "List of Values " including a table value and numbers below it

So basically say I have a table called "Device" and then one of the columns is "Quantity," what if I wanted to create a list of values that takes that number, say the quantity is 4, and the values are (quantity - 1) until !> 0, so in this case (4, 3, 2, 1)
I am using Oracle APEX and am assuming I need a dynamic LOV based on a sql query, but not sure how to get this. I've never used a for loop with PL/SQL
Thanks
You don't need loops for this.
select level
from dual
connect by level <= 4
order by level desc;
This should do it. Make sure that where I've put /* xxx */ you include a where clause that comes up with only 1 record. Most likely, you will use the ID of the Device table here.
SELECT ROWNUM display_value
, ROWNUM return_value
FROM DUAL
CONNECT BY ROWNUM <= (SELECT Quantity FROM Device WHERE /* xxx */)
ORDER BY ROWNUM DESC;

Sorting by value returned by a function in oracle

I have a function that returns a value and displays a similarity between tracks, i want the returned result to be ordered by this returned value, but i cannot figure out a way on how to do it, here is what i have already tried:
CREATE OR REPLACE PROCEDURE proc_list_similar_tracks(frstTrack IN tracks.track_id%TYPE)
AS
sim number;
res tracks%rowtype;
chosenTrack tracks%rowtype;
BEGIN
select * into chosenTrack from tracks where track_id = frstTrack;
dbms_output.put_line('similarity between');
FOR res IN (select * from tracks WHERE ROWNUM <= 10)LOOP
SELECT * INTO sim FROM ( SELECT func_similarity(frstTrack, res.track_id)from dual order by sim) order by sim; //that's where i am getting the value and where i am trying to order
dbms_output.put_line( chosenTrack.track_name || '(' ||frstTrack|| ') and ' || res.track_name || '(' ||res.track_id|| ') ---->' || sim);
END LOOP;
END proc_list_similar_tracks;
/
declare
begin
proc_list_similar_tracks(437830);
end;
/
no errors are given, the list is just presented unsorted, is it not possible to order by a value that was returned by a function? if so, how do i accomplish something like this? or am i just doing something horribly wrong?
Any help will be appreciated
In the interests of (over-)optimisation I would avoid ordering by a function if I could possibly avoid it; especially one that queries other tables. If you're querying a table you should be able to add that part to your current query, which enables you to use it normally.
However, let's look at your function:
There's no point using DBMS_OUTPUT for anything but debugging unless you're going to be there looking at exactly what is output every time the function is run; you could remove these lines.
The following is used only for a DBMS_OUTPUT and is therefore an unnecessary SELECT and can be removed:
select * into chosenTrack from tracks where track_id = frstTrack;
You're selecting a random 10 rows from the table TRACKS; why?
FOR res IN (select * from tracks WHERE ROWNUM <= 10)LOOP
Your ORDER BY, order by sim, is ordering by a non-existent column as the column SIM hasn't been declared within the scope of the SELECT
Your ORDER BY is asking for the least similar as the default sort order is ascending (this may be correct but it seems wrong?)
Your function is not a function, it's a procedure (one without an OUT parameter).
Your SELECT INTO is attempting to place multiple rows into a single-row variable.
Assuming your "function" is altered to provide the maximum similarity between the parameter and a random 10 TRACK_IDs it might look as follows:
create or replace function list_similar_tracks (
frstTrack in tracks.track_id%type
) return number is
sim number;
begin
select max(func_similarity(frstTrack, track_id)) into sim
from tracks
where rownum <= 10
;
return sim;
end list_similar_tracks;
/
However, the name of the function seems to preclude that this is what you're actually attempting to do.
From your comments, your question is actually:
I have the following code; how do I print the top 10 function results? The current results are returned unsorted.
declare
sim number;
begin
for res in ( select * from tracks ) loop
select * into sim
from ( select func_similarity(var1, var2)
from dual
order by sim
)
order by sim;
end loop;
end;
/
The problem with the above is firstly that you're ordering by the variable sim, which is NULL in the first instance but changes thereafter. However, the select from DUAL is only a single row, which means you're randomly ordering by a single row. This brings us back to my point at the top - use SQL where possible.
In this case you can simply SELECT from the table TRACKS and order by the function result. To do this you need to give the column created by your function result an alias (or order by the positional argument as already described in Emmanuel's answer).
For instance:
select func_similarity(var1, var2) as function_result
from dual
Putting this together the code becomes:
begin
for res in ( select *
from ( select func_similarity(variable, track_id) as f
from tracks
order by f desc
)
where rownum <= 10 ) loop
-- do something
end loop;
end;
/
You have a query using a function, let's say something like:
select t.field1, t.field2, ..., function1(t.field1), ...
from table1 t
where ...
Oracle supports order by clause with column indexes, i.e. if the field returned by the function is the nth one in the select (here, field1 is in position 1, field2 in position 2), you just have to add:
order by n
For instance:
select t.field1, function1(t.field1) c2
from table1 t
where ...
order by 2 /* 2 being the index of the column computed by the function */

Create Manual Link in Oracle Apex

I have created a line chart using below code.
select * from (
select
'f?p=&APP_ID.:41:&SESSION.:SUBMIT:&DEBUG.::P41_FROM_STOCK_ID,P41_TO_STOCK_ID:s.from_id,s.to_id' LINK,
s.from_id || '-' || s.to_id LABEL,
sum(util.find_usage_from_stock(MATERIAL_THIKNESS,s.from_id,s.to_id)) -
sum(util.find_sheets_sold(MATERIAL_THIKNESS,s.from_id,s.to_id)) diff
from material m, (select lag(stock_id, 1, stock_id) over (order by stock_date) from_id, stock_id to_id
from STOCK
where stock_time not like 'NEW_STOCK') s
where m.active like 'Y'
group by s.from_id,s.to_id
order by s.from_id desc
)
WHERE rownum <= 20
ORDER BY rownum DESC;
when click on a circle in line chart, should redirect to a link. but i have trouble with LINK in above query. when i click on a circle, redirect to url like below.
http://127.0.0.1:8080/apex/f?p=110:41:2026929503975702:SUBMIT:NO::P41_FROM_STOCK_ID,P41_TO_STOCK_ID:s.from_id,s.to_id
but i need to assign values into s.from_id,s.to_id in above url when i click on a circle in my chart.
how can i do that ?
Don't you just need to take the values from the query and concatenate those to your link string?, like this:
'f?p='||:APP_ID||':41:'||:APP_SESSION||':SUBMIT:'||:DEBUG||'::P41_FROM_STOCK_ID,P41_TO_STOCK_ID:'||s.from_id||','||s.to_id LINK

Resources