How to make a good procedure in PL/SQL? - oracle

so I have just started to create procedure in pl/sql but my skills is very limited. I have this table:
bank_account (
NUM_CC NUMBER(10) CONSTRAINT PK_NUMCC PRIMARY KEY,
NUM_CLIENT NUMBER(10),
SOLD NUMBER(10)
)
I want to create a procedure to transfer an amount 'm' on my account, so i have write this procedure :
Create or replace procedure virement-cc(num-client number, num-cc number , m number)AS
Begin
UPDATE bank_account
SET SOLD = SOLD+m
WHERE NUM_CLIENT = num-client
AND NUM_CC = num-cc ;
End ;
This is procedure is not good but i would like to know how to improve it to resolve my problem. Thank you all.

don't use hyphen but underline
don't name parameters as columns; prefix them with e.g. p_. Otherwise, Oracle will simply do nothing (but set column's name to its current value) and you'd have impression that nothing happened
So:
Create or replace procedure virement_cc
(p_num_client number, p_num_cc number, p_m number)
AS
Begin
UPDATE bank_account
SET SOLD = SOLD + p_m
WHERE NUM_CLIENT = p_num_client
AND NUM_CC = p_num_cc;
End ;

You need to distinguish between 'num_cc' the input parameter and 'num_cc' the column name. Rename 'num_cc' the input parameter as 'p_num_cc'.
Your WHERE clause has an issue:
WHERE NUM_CLIENT = p_num_client
AND NUM_CC = p_num_cc ;
(I've gone ahead and renamed your input parameter)
If NUM_CC is the primary key (it is) then it uniquely identifies a particular role, so there is no need to include a comparison on num_client. And with that you don't even need an input parameter for it.
Give more thought to your naming conventions
I name all of my table columns in the format 'adjective_noun'. And don't be afraid to be descriptive. Instead of NUM_CC, how about CARD_NUMBER. Instead of NUM_CLIENT, try CLIENT_NUMBER. This 'adjective_noun' format also has the advantage of absolutely eliminating the possibility of accidentally trying to use a reserved or key word.
I name all of my parameters P_'adjective_noun'
I name all of my internal variables V_'adjective_noun'.
You may well decide on different naming standards. They key is to actually have naming standards, and that those standards be well thought out an reasoned.

Related

Can anyone show me how to write a update stored procedure in the sql server whose primary key is of type uniqueidentifier?

ALTER PROCEDURE [dbo].[Update]
-- Add the parameters for the stored procedure here
#Category_Code nvarchar(20),
#Category_Name nvarchar(167),
#About_Category nvarchar(max),
#Parent_Category_Id uniqueidentifier,
#Is_Enable bit,
#Is_Active bit,
#Is_Block bit,
#Category_Id uniqueidentifier
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
Update Category
SET Category_Code = #Category_Code,
Category_Name = #Category_Name,
About_Category = #About_Category,
Parent_Category_Id = #Parent_Category_Id,
Is_Enable = #Is_Enable,
Is_Active = #Is_Active,
Is_Block = #Is_Block
WHERE Category_Id = #Category_Id
END
this is my stored procedure but it cannot update the records. Why?
Unique identifiers are one of the fundamental blocks of data modeling and well as data consumption.A GUID in SQL Server can generate unique IDs with the least probability of the exact ID being generated.GUIDs are typically 128-bit in size and 32 digits long in the pattern of 8 digits – 4 digits – 4 digits – 4 digits – 12 digits.
newid(), NewSequentialId() is inbuilt function which generates the random unique identifiers. Newid() is generates random id but the NewSequentialId() generates id in sequential manner. Try to update the unique identifiers with these in built functions.

Writing a Version Number Function in PL/SQL

I want to write a function that will give me the next version number for a table. The table stores the existing version on each record. For example,
I have the cat table
cats
seqid 1
name Mr Smith
version number 1.2b.3.4
How can I write a program that will be able to increment these values based on various conditions?
This is my first attempt
if v_username is not null
then v_new_nbr = substr(v_cur_nbr, 1,7)||to_number(substr(v_cur_nbr, 8,1))+1
should be 1.2b.3.5
substr(v_cur_nbr, 1,7)||to_number(substr(v_cur_nbr, 8,1))+1
This hurls ORA-01722: invalid number. The reason is a subtle one. It seems Oracle applies the concatenation operator before the additions, so effectively you're adding one to the string '1.2b.3.4'.
One solution is using a TO_CHAR function to bracket the addition with the second substring before concatenating the result with the first substring:
substr(v_cur_nbr, 1,7) || to_char(to_number(substr(v_cur_nbr, 8,1))+1)
Working demo on db<>fiddle.
Incidentally, a key like this is a bad piece of data modelling. Smart keys are dumb. They always lead to horrible SQL (as you're finding) and risk data corruption. A proper model would have separate columns for each element of the version number. We can use virtual columns to concatenate the version number for display circumstances.
create table cats(
seqid number
,name varchar2(32)
,major_ver_no1 number
,major_ver_no2 number
,variant varchar2(1)
,minor_ver_no1 number
,minor_ver_no2 number
,v_cur_nbr varchar2(16) generated always as (to_char(major_ver_no1,'FM9') ||'.'||
to_char(major_ver_no2,'FM9') ||'.'||
variant ||'.'||
to_char(minor_ver_no1,'FM9') ||'.'||
to_char(minor_ver_no2,'FM9') ) );
So the set-up is a bit of a nause but incrementing the version numbers is a piece of cake.
update cats
set major_ver_no1 = major_ver_no1 +1
, major_ver_no2 = 0
, variant = 'a';
There's a db<>fiddle for that too.
Try searching mask for TO_NUMBER to be able to get the decimal number, this small example might help:
CREATE TABLE tmp_table (version varchar2(100));
INSERT INTO tmp_table(version) VALUES ('1.2b.3.4');
DECLARE
mainVersion NUMBER;
subVersion NUMBER;
currentVersion VARCHAR2(100);
BEGIN
SELECT version INTO currentVersion FROM tmp_table;
mainVersion := TO_NUMBER(SUBSTR(currentVersion,1,3),'9.9') + 0.1;
subVersion := TO_NUMBER(SUBSTR(currentVersion,6,3),'9.9') + 1.1;
UPDATE tmp_table SET version = (mainVersion||'b.'||subVersion);
END;

Can I create a fixed length type in oracle database?

Using Oracle 11gR2, I have a need to create a fixed length string comprised of 200 + fields from a table.
I have created a dynamic select statement that creates this by reading a table that has the relationship between the fixed length string and the database fields. I end up with something like;
select rpad(char_field1, 20,' ') ||
lpad(num_field1,6,'0') ||
rpad(' ',8,' ') AS FIXED_STRING
from my_table
It works fine, but is CPU intensive with all the concatenation and padding etc.
I noticed that there is the ability to create an external table of type fixed, but my data never needs to be written to disk, just passed to a program for processing.
I wondered if there was an equivalent in memory structure similar to;
TYPE MY_RECORD_TYPE IS RECORD
(
CHAR_FIELD1 position(1:20) VARCHAR2(20),
NUM_FIELD2 position(21:6) NUMBER(6),
FILL_FIELD1 position(28,8) VARCHAR2(8)
);
That would allow me to create a string to pass to something else, in my case VB.NET?
My overall goal is to come up with the most efficient way of creating fixed length strings from column data in a table.
Virtual Columns might work for you - hard to tell from the information given. On the table itself you define the virtual column - which will concatenate the fields you are interested in.
ALTER TABLE YOUR_TABLE
ADD (FIXED_STRING char(34) Generated Always as
(rpad(char_field1, 20,' ') || lpad(num_field1,6,'0') || rpad(' ',8,' ') ));
The virtual column can then be indexed, etc...

Determining input datatype Oracle/PLSQL

I am writing a PLSQL 'INSTEAD OF INSERT' Trigger whereby the ID field (GID) can be inserted as either a string or a number. If the GID value is a string I would like to attempt to convert that into the correct GID (number) otherwise if a number is input the script will continue.
The part I am struggling with here is determining the datatype of ':New.CHART_GID' - is this possible in PLSQL? I can't check for chars in the string as the string may only contain numbers in some instances.
Thanks.
You can use TRANSLATE to check if there is something other as numbers:
CREATE OR REPLACE TRIGGER trigger_name
INSTEAD OF INSERT
ON table_name
FOR EACH ROW
DECLARE
vGID INTEGER;
...... other things
BEGIN
IF :New.CHART_GID is not null AND TRANSLATE(:New.CHART_GID,'0123456789',' ') is null THEN
vGID := TO_NUMBER(:New.CHART_GID);
.... do what you want with number
ELSE
... do what you want with not number
END IF;
.... other things
END;
CHART_GID have to be varchar2 in the view
I realise what I was trying to achieve was actually not possible. The solution for me was actually to join the Chart_no into the view and insert into either that field of the GID. If I input a Chart_no the GID field would be automatically populated and the same for if I input a GID.

Sequence with variable

In SQL we will be having a sequence. But it should be appended to a variable like this
M1,M2,M3,M4....
Any way of doing this ?
Consider having the prefix stored in a separate column in the table, e.g.:
CREATE TABLE mytable (
idprefix VARCHAR2(1) NOT NULL,
id NUMBER NOT NULL,
CONSTRAINT mypk PRIMARY KEY (idprefix, id)
);
In the application, or in a view, you can concatenate the values together. Or, in 11g you can create a virtual column that concatenates them.
I give it 99% odds that someone will say "we want to search for ID 12345 regardless of the prefix" and this design means you can have a nice index lookup instead of a "LIKE '%12345'".
select 'M' || my_sequence.nextval from dual;

Resources