I am having a bit of an issue in our code.
There is a procedure that creates a dynamic trigger.
However, it creates a cursor that is longer then 30 characters.
I know what variable is making those cursors.
Does anyone know a way to limit the characters to a max. of 30?
Like, if this variable is longer then 30 characters, then cut it off.
I could find an expample, so I hope that is even possible.
You can chop off characters with substr(variable, 1, 30).
For instance:
declare
cursor_name varchar(100);
begin
cursor_name := '012345678901234567890123456789ABCDE';
cursor_name := substr(cursor_name, 1, 30);
dbms_output.put_line(cursor_name);
end;
... will output:
012345678901234567890123456789
Related
All,
I am trying to nest a macro within a macro but am unsuccessful. The Start_Cycle variable is set every few months and updated manually. I want to create a start_point variable that goes back 6 months and I successfully created it, however, the output includes a space after the %STR as seen below
%let start_cycle = '01JUL2022:00:00:00'dt; /set to beginning month of this cycle/
%let start_point = %STR(%')%sysfunc(intnx(DTMONTH,&start_cycle.,-6,b),datetime19.)%STR(%')dt;
%put &start_point;
Output below
%let start_cycle = '01JUL2022:00:00:00'dt; /set to beginning month of this cycle/
%let start_point =
%STR(%')%sysfunc(intnx(DTMONTH,&start_cycle.,-6,b),datetime19.)%STR(%')dt;
%put &start_point; ' 01JAN2022:00:00:00'dt
^^Does anyone know why there is a space after the single quote? ' 01JAN2022:00:00:00'dt
Since it runs without issues, I decided to create another macro variable that does the same thing, but instead, the output needs to be converted to a character string in this format below (current Macro)
%let start_pointSales = '2022/01';
I tried multiple times using different ways of going about this, spent many hours looking through forum from SAS Communities to StackOverflow and even SAS youtube videos to no luck. Anyone have any luck in combating this?
To-Be Macro:
%let NEW_start_pointSales = %sysfunc(intnx(month,&start_cycle.,-6,b),yymms.);
%put &NEW_start_pointSales;
The NEW_start_pointSales will be used in the WHERE clause with Data type Varchar (21) using PROC SQL.
left join EDWSALE.DSCOE_LLD (where=( &NEW_start_pointSales. <= SALES_MONTH < &end_pointSales.
Output Error below:
NOTE: Writing TAGSETS.SASREPORT13(EGSR) Body file: EGSR
24
25 GOPTIONS ACCESSIBLE;
WARNING: An argument to the function INTNX referenced by the %SYSFUNC or %QSYSFUNC macro function is out of range.
NOTE: Mathematical operations could not be performed during %SYSFUNC function execution. The result of the operations have been set
to a missing value.
Any help is appreciated!
You cannot apply a format, YYMMS, designed to work on DAYS to a value that is in SECONDS. If you want to use a date format on a datetime value you need to convert the value from seconds to days. You could use the DATEPART() function or just divide by the number of seconds in a day.
Why are you trying to compare a variable that is CHARACTER to numbers? If you generate a macro variable with a string like 2022/01 and then use it to generate code like:
&NEW_start_pointSales. <= SALES_MONTH
that will result in code like:
2022/01 <= SALES_MONTH
which is comparing the number 2022 (any number divided by 1 is itself) to the value SALES_MONTH, which you just said was a character string.
What types of strings does SALES_MONTH contain? That will determine how (or whether) you can make inequality tests against it.
PS There is space in the output of DATETIME19 because that is how that particular format works. Note that there is a bug in the DATETIME format and you cannot use DATETIME18. to produce a string with four digits for the year even though only 18 characters would be used. The extra space does not matter to using the string in a datetime literal as the DATETIME informat will recognize the string even with the extra space.
I have an oracle 19c ee database build via their docker image on Oracles github (https://github.com/oracle/docker-images/tree/master/OracleDatabase/SingleInstance). I am trying to follow their example as to how to create a function from here.
I have copied their example exactly. Setup table and data:
CREATE TABLE orders (
customer_id number(10),
order_total NUMBER(11,2)
);
INSERT INTO orders (customer_id, order_total) VALUES (1, 200.01)
The actual function:
CREATE FUNCTION get_bal(acc_no IN NUMBER)
RETURN NUMBER
IS acc_bal NUMBER(11,2);
BEGIN
SELECT order_total
INTO acc_bal
FROM orders
WHERE customer_id = acc_no;
RETURN(acc_bal);
END;
However I keep running into this error when I try and create the function
Query 2 ERROR: ORA-06550: line 5, column 27:
PL/SQL: ORA-00904: "ACC_NO": invalid identifier
ORA-06550: line 2, column 7:
PL/SQL: SQL Statement ignored
ORA-06550: line 6, column 7:
PLS-00372: In a procedure, RETURN statement cannot contain an expression
ORA-06550: line 6, column 7:
PL/SQL: Statement ignored
What am I doing wrong?
The example works for me. You must have mistyped something. Are you sure your function is exactly the same as the one in the manual?
ORA-00904: "ACC_NO": invalid identifier
suggests the declaration acc_bal NUMBER(11,2); is missing or different.
PLS-00372: In a procedure, RETURN statement cannot contain an expression
indicates that your code is a procedure, not a function.
SQL> CREATE TABLE orders (
2 customer_id number(10),
3 order_total NUMBER(11,2)
4 );
Table created
SQL> INSERT INTO orders (customer_id, order_total) VALUES (1, 200.01);
1 row inserted
SQL> CREATE FUNCTION get_bal(acc_no IN NUMBER)
2 RETURN NUMBER
3 IS acc_bal NUMBER(11,2);
4 BEGIN
5 SELECT order_total
6 INTO acc_bal
7 FROM orders
8 WHERE customer_id = acc_no;
9 RETURN(acc_bal);
10 END;
11 /
Function created
SQL> select get_bal(1) from dual;
GET_BAL(1)
----------
200.01
As an aside, while I'm a big fan of the Oracle documentation in general, and this example does neatly illustrate how to create a PL/SQL function, I think it could be improved:
For readability, it's better to give each declaration its own line, so line 3 would be better split into two with acc_bal NUMBER(11,2); on its own line.
The IS and AS keywords are interchangeable here, but surely create ... as (similar to what you might use to create a table or a view) reads better than create ... is.
Understandably, the author didn't want to complicate the example by introducing %type before it had been explained, but a more advanced version would use acc_bal orders.order_total%type; to make acc_bal inherit its datatype from the table column rather than hard-coding it. This goes for all three values used in the function.
The parameter and variable names are OK - they are at least clear - but there is a danger when using the same naming pattern for parameters and variables as for table columns. One day you will type WHERE c.customer_id = customer_id and wonder why you're getting more rows back than you expected. Again it's understandable that the author didn't want to get into that whole discussion in the first example, but it's something to think about. You might use get_bal.acc_no within the function, or use camelCase for parameters and variables, or prefix them with p_ for 'parameter' etc.
A basic rule of layout is that opening and closing keywords such as if/else and begin/end should be left-aligned. The END at line 10 is misaligned under its opening BEGIN. I suppose indenting the entire thing after the first line is a valid personal layout choice, but to me it doesn't add anything.
It's a good idea to leave blank lines around each SQL statement, to avoid a solid wall of text. Personally, I'd prefer a blank line before the RETURN at line 9.
A RETURN clause doesn't require any brackets. The compiler is ignoring the redundant brackets at line 9. I'd lose them.
It's good practice (though optional) to include the procedure/function name in the closing END, so line 10 would become END get_bal;
The COBOL-style uppercase habit is widespread in the industry, but there is no need for it. (PL/SQL's syntax is famously based on Ada, though some also point to ALGOL and PL/1 - nobody ever wrote those in uppercase.) I would improve readability by lowercasing the whole thing.
With these changes, I get this:
create or replace function get_bal
( inAccNo in orders.customer_id%type )
return orders.order_total%type
as
accBal orders.order_total%type;
begin
select order_total into accBal
from orders
where customer_id = inAccNo;
return accBal;
end;
I have this strange symbol on my pl/sql developer client (check image it's the symbol between P and B )
In the past, and for a different symbol, i was able to update my DB and remove them making this:
update table set ent_name = replace(ent_name, UTL_RAW.CAST_TO_VARCHAR2(HEXTORAW('C29B')), ' ');
The problem is that i dont remember how I translated the symbol (i had at that time) to the C29B.
Can you help me to understand how can i translate the currenct symbol to the HEX format, to i can use the command to remove it from my database?
Thanks
As long as it's in your table, you can use the DUMP function to find it.
Use DUMP to get the byte representation of the data in code of you wish to inspect for weirdness.
A good overview: Oracle / PLSQL: DUMP Function
Here's some text with plain ASCII:
select dump('Dashes-and "smart quotes"') from dual;
Typ=96 Len=25:
68,97,115,104,101,115,45,97,110,100,32,34,115,109,97,114,116,32,113,117,111,116,101,115,34
Now introduce funny characters:
select dump('Dashes—and “smart quotes”') from dual;
Typ=96 Len=31:
68,97,115,104,101,115,226,128,148,97,110,100,32,226,128,156,115,109,97,114,116,32,113,117,111,116,101,115,226,128,157
In this case, the number of bytes increased because my DB is using UTF8. Numbers outside of the valid range for ASCII stand out and can be inspected further.
The ASCIISTR function provides an even more convenient way to see the special characters:
select asciistr('Dashes—and “smart quotes”') from dual;
Dashes\2014and \201Csmart quotes\201D
This one converts non-ASCII characters into backslashed Unicode hex.
The DUMP function takes an additional argument that can be used to format the output in a nice way:
select DUMP('Thumbs 👍', 1017) from dual;
Typ=96 Len=11 CharacterSet=AL32UTF8: T,h,u,m,b,s, ,f0,9f,91,8d
select DUMP('Smiley 😊 Face', 17) from dual;
Typ=96 Len=16: S,m,i,l,e,y, ,f0,9f,98,8a, ,F,a,c,e
I wrote a program which accepts an integer as input and prints the integer as output in Ada. When i run the program, it's printing the number but there are several leading white spaces. Does anybody know why it's happening? Here's the code:
with Ada.Text_IO, Ada.Float_Text_IO, Ada.Integer_Text_IO;
use Ada;
procedure Solution is
Int: Integer;
begin
Integer_Text_IO.Get (Int);
Integer_Text_IO.Put (Int);
end Solution;
Leading white spaces are mandated by the standard: "If the resulting sequence of characters to be output has fewer than Width characters, then leading spaces are first output to make up the difference." RM A.10.8(13).
If you want a different behaviour, specify width, like this:
Integer_Text_IO.Put (Int, Width => 1);
The definition for the Put procedure has the width parameter as being on type Field. Its definition is...
subtype Field is Integer range 0 .. implementation-defined;
I'd recommend putting a field width of 0, which I think stands out more than 1.
Alternatively you could just set the default field width...
Ada.Integer_Text_IO.Default_Width = 0;
in the startup section of your program, which will ensure that all output from this package has no leading spaces.
I'm new to PL/SQL, doing a homework question where I need to write a procedure that returns an error message based on day of week/time but I am stuck on a basic thing before I get to that point:
I have written the following:
CREATE OR REPLACE PROCEDURE
SECURE_IT
(p_weekday NUMBER,
p_currtime TIME)
IS
BEGIN
select to_char(current_timestamp,'D')
, to_char(current_timestamp,'HH24:MI')
into p_weekday, p_currtime
from dual;
DBMS_OUTPUT.PUT_LINE(p_weekday,p_currtime);
END;
I think all of my ;'s are all in place, can't see any difference between this, code in the book, and code I've found online yet still it returns this error:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the
following: ; <an identifier> <a double-quoted delimited-identifier>
current delete exists prior <a single-quoted SQL string> The symbol ";"
was substituted for "end-of-file" to continue.
I tried changing END; to END SECURE_IT; in hopes that it would fix something (all I could think of) but can't see what's wrong. Could someone help me with this?
Thank you in advance :-)
There is a couple of mistakes in your procedure
TIME datatype (In PL/SQL there is no such datatype see Documentation, Alternatively, you can pass datetime data types: DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL TIME ZONE)
You can extract time part using many options. For example:
SELECT TO_CHAR(p_currDateTime, 'HH24:MI:SS') into p_currtime FROM DUAL;
You are trying to update p_weekday & p_currtime which are IN parameters. These parameters are used to pass value to the procedure, and not to return ones.
DBMS_OUTPUT.PUT_LINE takes only one parameter, so instead of , you can concatenate the two values like this: DBMS_OUTPUT.PUT_LINE(p_weekday||'-'||p_currtime);
It would help a great deal if it is not clear what are you trying to achieve by this procedure
Basically what i can see here is you need to print some value out od procedure as a part of your homework. But using dbms_output will not do any good. You need to make these as OUT param to use these values any where.
CREATE OR REPLACE PROCEDURE SECURE_IT(
p_weekday OUT VARCHAR2,
p_currtime OUT VARCHAR2)
IS
BEGIN
p_weekday := TO_CHAR(CURRENT_TIMESTAMP,'D');
p_currtime:= TO_CHAR(CURRENT_TIMESTAMP,'HH24:MI');
DBMS_OUTPUT.PUT_LINE(p_weekday||' '||p_currtime);
END;
-----------------------------EXECUTE--------------------------------------------
var week VARChaR2(100);
var curtime VARChaR2(100);
EXEC SECURE_IT(:week,:curtime);
print week;
print curtime;
-------------------------------OUTPUT--------------------------------------------
WEEK
-
6
CURTIME
-----
06:12
-------------------------------OUTPUT----------------------------------------------