Are dynamic variables possible in SQR (not dynamic SQL) - peoplesoft

I'm writing an SQR program to send a vendor a file containing employee info. The file contains a number of fields for which I've assigned the variables
$Code_1
$Code_2
$Code_3
....
Each code has an associated rate, and I've assigned similar variables ($Rate_1, $Rate_2, etc...)
I have a lookup table that has the columns EMPLID, JOBCODE, HOURLY_RT. I need to loop through for each employee to get all of the codes/rates. It's possible that some employees will have more/fewer than others. Is it possible to have "dynamic" variables, like we do for dynamic sql? For example, something like $Code_[$i]? The thought was to do something like this:
let #i = 1
begin-select
EC.JOBCODE
EC.HOURLY_RT
let $Code_[$i] = &EC.JOBCODE
let $Rate_[$i] = &EC.HOURLY_RT
let #i = #i + 1
FROM PS_ACME_LOOKUP EC
WHERE EC.EMPLID = &J.EMPLID
end-select
This doesn't work, but I wondering if there's a similar (or better) way to accomplish this. I suppose I could do an evaluate of the counter: when #i = 1, $Code_1 = ... when #i=2, $Code_2 =... But I'm hoping there's a better way.
Thanks
Edit - Just for added clarification, for each employee, a single line will be written to a file, with the fields for each of these values (populated or not) - so the line will have:
$EMPLID $Code_1 $Code_2 $Code_3.....$Rate_1 $Rate_2 $Rate_3
For further clarification the lookup table will have multiple rows for each employee, so the table might look like this:
EMPLID JOBCODE HOURLY_RT
0001 ABC 10.50
0001 DEF 9.75
0001 GHI 9.50
When I populate the variables, looping through the table, I would want $Code_1 = 'ABC', $Rate_1 = 10.50, $Code_2 = 'DEF', Rate_2 = 9.75 etc...

You can use arrays in SQR.
To set up the array:
Create-Array Name=WorkArray Size = 100
Field=Code
Field=Rate
Let #NumCodesForEmp = 0
To add data in your Select Block - also use on-break before and after procedures:
Begin-Select
EC.Emplid () on-break print=never before=Init-Emp After=Process-Emp
Let $Emplid = &EC.Emplid
add 1 to #NumCodesForEmp
Put &EC.JobCode &EC.Rate into WorkArray(#NumCodesForEmp) Code Rate
Write the before procedure to initialize:
Begin-Procedure Init-Emp
Let #NumCodesForEmp = 0
End-Procedure
When done with the employee:
Begin-Procedure Process-Emp
Let #I = 1
Let $OutputLine = $Emplid
While #I <= #NumCodesForEmp
Get $Code $Rate From WorkArray(#I) Code Rate
Let $OutputLine = $Outputline || ',' || $Code || ',' || $Rate
add 1 to #I
End-While
! This assumes that file number 10 is open
Write #10 from $OutputLine
End-Procedure
However, I think you could do everything without an array - use the before and after procedures as so:
Begin-Procedure Init-Emp
Let $OutputLine = &EC.Emplid
End-Procedure
Begin-Procedure Process-Emp
Write #10 from $OutputLine
End-Procedure
Then the Select Block would look like this:
Begin-Select
EC.Emplid () on-break print=never before=Init-Emp After=Process-Emp
EC.JobCode
EC.Rate
Let $OutputLine = $OutputLine || ',' || &EC.Jobcode || ',' || &EC.Rate
When using on-break, make sure you sort by emplid. This is much simpler if your need is just to write a file from data from a table.

Related

sqlite query for getting a value from a column containing multiple values

I have a simple table that looks like below
I need to find the 'ID' which has the Number 3, so i wrote a query like below
select * from IDtable where Number like '%3%'
it is actually returning all the ID since i have used like and the Number contains many values starting with 3, how do i get the id which contains 3
Concatenate a , at the start and at the end of the column and check if it contains ',3,' with the operator LIKE:
SELECT *
FROM IDtable
WHERE ',' || Number || ',' LIKE '%,3,%'
or with INSTR():
SELECT *
FROM IDtable
WHERE INSTR(',' || Number || ',', ',3,')
In Python, you should use a ? placeholder for the parameter "3":
n = "3"
sql = """
SELECT *
FROM IDtable
WHERE ',' || Number || ',' LIKE '%,' || ? || ',%'
"""
cursor.execute(sql, (n,))
Note that a normalized table like:
ID
Number
Ab
2
Ab
9
Ab
16
...
......
cD
3
cD
10
cD
17
...
......
would save you all the trouble of querying with a complicated string expression which may prove bad for performance.

How to repeat (recursive) query, again and again?

[EDIT]
Ah.. How can I put "IF" condition when iterate ? sometimes there are no Tags at all.
In that case I do not want any kind of modification.
I wrote query like this;
UPDATE myTable SET myCOL =
substr(myCOL, 1, instr(myCOL, '<Tag>') - 1)
|| '■' ||
substr(myCOL, instr(myCOL, '</Tag>') + 6, length(myCOL));
Because I'd like to achive like this;
myVar := "abc<Tag>BuLah..BuLah..</Tag>def"
myGoal := "abc■def"
So far so good.
Now, things goes to the real world, I have myVar like this;
myVar := "abc<Tag>BuLah1..</Tag>def..ghi<Tag>BuLah2..</Tag>jkl"
How can I achieve my goal ?
Thanks..
[EDIT] Text files attached for the moment.
Link Deleted...
simple extracted text, all ROWs - 811 rows
simple extracted text, all ROWs Tags processed
simple extracted text, Tags ROWs only - 18 rows, 42 tags.
When I execute without this query, its runtime instantly. No time needed. But, when I exectue with this query, it took me 71 seconds to finish. I guess I have made some.. bad bug or something. The other XML parts have handled by the other query, this query deals above mentioned Tags only.
With a recursive CTE:
with recursive cte as (
select myCOL,
substr(myCOL, 1, instr(myCOL, '<Tag>') - 1)
|| '■' ||
substr(myCOL, instr(myCOL, '</Tag>') + 6, length(myCOL)) newCOL
from myTable
where myCOL like '%<Tag>%'
union all
select c.myCOL,
substr(c.newCOL, 1, instr(c.newCOL, '<Tag>') - 1)
|| '■' ||
substr(c.newCOL, instr(c.newCOL, '</Tag>') + 6, length(c.newCOL)) newCOL
from cte c
where c.newCOL like '%<Tag>%'
)
update myTable
set myCOL = (
select newCOL from cte
where myTable.myCOL = cte.myCOL and cte.newCOL not like '%<Tag>%'
)
where myCOL like '%<Tag>%';
See the demo.
Results:
| myCOL |
| ---------------- |
| abc■def |
| abc■def..ghi■jkl |

SQR Procedure parameters/arguments

I'm trying to understand more about how arguments/parameters are used when calling and executing procedures. I understand that procedures that contain an parameter with a leading colon (:) pass back values to the calling DO command, however I think what it a little confusing is it appears that the variables names from what the calling DO command issues, and what the procedure (called by DO) returns don't necessarily have to be the same name. If someone could help shed some light on the following examples and explain what values are being either passed to/from or how their referenced by the issuing DO command that would be helpful.
It looks like the call to run the Get-Recursive-Reports-To (do Get-Recursive-Reports-To($Recursive_Line, $_POSITION_NBR, #_Global_Counter) is issuing these 3 variables as parameters to the procedure Get-Recursive-Reports-To, however as I look through the Get-Recursive-Reports-To procedure, I do not see any references of the variable $Recursive_Line within this procedure, so is the procedure actually using it or what is the purpose of including it? Similar question with $_val_Position_NBR, where is this variable getting it's value assigned from?
And then within the Get-Recursive-Reports-To procedure I see a parameter - :$var_Next_EMPLID that I believe is being passed back to the calling DO in the Run-Recursion procedure, but I can not figure out how/where it uses the value passed back to it...
begin-procedure Run-Recursion
let #_Global_Counter = 0
let $Recursive_Line = ''
let $Data_Line_EMPL = ''
let $Data_Line_EMPL = $_BUSINESS_UNIT || '|' || $_BUSINESS_UNIT_DESCR || '|' || '2019' || '|' ||
$_EMPLID || '|' || $_NAME || '|' || $_DEPTID || '|' || $_DEPT_DECSR || '|' || $_JOBCODE || '|'
do Get-Recursive-Reports-To($Recursive_Line, $_POSITION_NBR, #_Global_Counter)
let $Data_Line_EMPL = $Data_Line_EMPL || $Recursive_Line
do Write-Data-Line($Data_Line_EMPL)
end-procedure
begin-procedure Get-Recursive-Reports-To(:$val_Data_Line, $val_Current_Position_Nbr, #Recursion_Counter)
let #Recursion_Counter = #Recursion_Counter + 1
do Get-the-ReportsTo-for-the-Current-Position($val_Current_Position_Nbr, $Next_Position_Nbr, $Next_EMPLID)
do Check-For-Stop($Stop_Recursion, $val_Current_Position_Nbr, $Next_Position_Nbr, #Recursion_Counter)
if $Stop_Recursion = 'N'
let $val_Data_Line = $val_Data_Line || $Next_EMPLID || '|'
do Get-Recursive-Reports-To($val_Data_Line, $Next_Position_Nbr, #Recursion_Counter)
end-if
end-procedure
begin-procedure Get-the-ReportsTo-for-the-Current-Position($_val_Position_NBR, :$var_ReportsTo, :$var_Next_EMPLID)
let #local_counter = 0
begin-select
G.REPORTS_TO &G.Reports_to
let $var_ReportsTo= &G.Reports_To
from PS_POSITION_DATA G
WHERE G.POSITION_NBR = $_val_Position_NBR
and G.EFF_STATUS = 'A'
AND (G.EFFDT =
(SELECT MAX(G_ED.EFFDT) FROM PS_POSITION_DATA G_ED
WHERE G.POSITION_NBR = G_ED.POSITION_NBR
AND G_ED.EFFDT <= $_As_OF_Date))
end-select
begin-select
H.EMPLID &H.EMPLID
Z.NAME &Z.NAME
let $var_Next_EMPLID= &H.EMPLID
let #local_counter = #local_counter + 1
from PS_JOB H !, PS_EMPLOYEES Z
WHERE H.POSITION_NBR = $var_ReportsTo
and H.EMPL_STATUS not in ('D', 'R', 'T')
and (H.EFFDT =
(SELECT MAX(H_ED.EFFDT) FROM PS_JOB H_ED
WHERE H.EMPLID = H_ED.EMPLID
AND H.EMPL_RCD = H_ED.EMPL_RCD
AND H_ED.EFFDT <= $_As_Of_Date))
end-select
if #local_counter > 1
let $var_Next_EMPLID = $local_counter || ' ' || 'Employees in this Position'
end-if
if #local_counter = 0
let $var_Next_EMPLID = 'Position Vacant'
end-if
end-procedure
The FIRST call to Get-Recursive-Reports-To from the main procedure uses the $Recursive_Line variable. It doesn't have to be referenced again because it's internal to the procedure.
Once IN procedure Get-Recursive-Reports-To, the name of this variable becomes $val_Data_Line and is used to call back to the same procedure Get-Recursive-Reports-To which can change it. I guess ergo the name, Get-Recursive-Reports-To.
Recursion is a pain in the neck but it looks like it's being used to go up an organizational chain, finding the reports to employee id, then getting the name of that person.
Variable $var_Next_EMPLID is passed from Get-the-ReportsTo-for-the-Current-Position back to the caller as variable $Next_Emplid which is then used again to call Get-Recursive-Reports-To.
I can't tell when or why the Recursion stops since you didn't include the procedure "Check-For-Stop". Looks like there is some check - perhaps if the $Val_Current_Position_Nbr or $Next_Position_Nbr is blank or equal or something.

How to execute a complex sql statement and get the results in an array?

I would like to execute a fairly complex SQL statement using SQLite.swift and get the result preferably in an array to use as a data source for a tableview. The statement looks like this:
SELECT defindex, AVG(price) FROM prices WHERE quality = 5 AND price_index != 0 GROUP BY defindex ORDER BY AVG(price) DESC
I was studying the SQLite.swift documentation to ind out how to do it properly, but I couldn't find a way. I could call prepare on the database and iterate through the Statement object, but that wouldn't be optimal performance wise.
Any help would be appreciated.
Most sequences in Swift can be unpacked into an array by simply wrapping the sequence itself in an array:
let stmt = db.prepare(
"SELECT defindex, AVG(price) FROM prices " +
"WHERE quality = 5 AND price_index != 0 " +
"GROUP BY defindex " +
"ORDER BY AVG(price) DESC"
)
let rows = Array(stmt)
Building a data source from this should be relatively straightforward at this point.
If you use the type-safe API, it would look like this:
let query = prices.select(defindex, average(price))
.filter(quality == 5 && price_index != 0)
.group(defindex)
.order(average(price).desc)
let rows = Array(query)

Simple Procedure raise ORA-06502

There's the simplified version of my code who keep raise me ORA-06502:
declare
p_filter varchar2(300) := '2012';
p_value varchar2(300) := '12345.000';
w_new_value number(13,3) := null ;
w_count number(4) := null ;
BEGIN
SELECT count(*)
INTO w_count
FROM dual
where p_filter = p_filter;
--- more filters
if w_count != 0 then
w_new_value := p_value / w_count;
else
w_new_value := p_value;
end if;
-- do something
end;
/
Someone can give me a help?
DataBase Details
nls_language = italian
nls_territory = italy
nls_currency = �
nls_iso_currency = italy
nls_numeric_characters = ,.
nls_calendar = gregorian
nls_date_format = dd-mon-rr
nls_date_language = italian
nls_characterset = we8iso8859p15
nls_sort = west_european
nls_time_format = hh24:mi:ssxff
nls_timestamp_format = dd-mon-rr hh24:mi:ssxff
nls_time_tz_format = hh24:mi:ssxff tzr
nls_timestamp_tz_format = dd-mon-rr hh24:mi:ssxff tzr
nls_dual_currency = �
nls_nchar_characterset = al16utf16
nls_comp = binary
nls_length_semantics = byte
nls_nchar_conv_excp = false
First, this is always going return a value of 1.
SELECT count(*)
INTO w_count
FROM dual
It doesn't matter what the qualifier is.
Lastly, I just ran your simplified code example in Oracle 11R2 and it didn't throw an exception.
I added the following statement in place of your "do something" comment:
dbms_output.put_line('w_new_value: ' || w_new_value || '. w_count: ' || w_count);
The result was:
w_new_value: 12345. w_count: 1
So, I think you've simplified your example into oblivion. You need to provide something that actually shows the error.
Good luck.
I found myself the ansewer and i think is useful for other know.
The real problem of the script for my DB is the language.
The italian "version" of Oracle accept , instead of the . for translate the VARCHAR2 into NUMBER unlike the most of other country.
For make the code running well the solution is
w_new_value := replace(p_value,'.',',') / w_count;
This trick finally allows the DB use my VARCHAR2 param like a NUMBER

Resources