PL/SQL Oracle dbms_output make evenly output - sql

I tried searching for an answer and found none.
I would love to make my output evenly even if the length of the article is different for each article.
this is what I have when the length are different
This is the code for the people intersted to look at
set serverout ON format WORD_WRAPPED;
CREATE OR REPLACE PROCEDURE imprimeFacture IS
CURSOR c_facture IS
SELECT
customer.contact as c_contact,
customer.address as c_address,
customer.city as c_city,
customer.state as C_state,
customer.zip as c_zip,
customer.phone as c_phone,
salesman.nom as s_nom,
salesman.address as s_address,
salesman.city as s_city,
salesman.state as s_state,
salesman.zip as s_zip,
salesman.phone as s_phone,
invoices.ino as i_ino,
invoices.idate as i_date,
detail.qty as d_qty,
parts.descript as p_description,
detail.price as d_prix,
detail.ltotal as d_prixTotal,
(
SELECT
round(SUM(detail.ltotal), 2)
FROM
detail
WHERE
detail.ino = 1054
) AS totalfacture,
(
SELECT
round(SUM(detail.ltotal * 0.15), 2)
FROM
detail
WHERE
detail.ino = 1054
) AS taxe,
(
SELECT
round(SUM(detail.ltotal * 0.15 + detail.ltotal), 2)
FROM
detail
WHERE
detail.ino = 1054
) AS totalavectaxe
FROM
invoices
JOIN detail ON detail.ino = invoices.ino
JOIN parts ON parts.pno = detail.pno
JOIN customer ON customer.cno = invoices.cno
JOIN salesman ON salesman.salesman = invoices.salesman
WHERE
invoices.ino = 1054;
rec_facture c_facture%rowtype;
fictifAvantBoucle NUMBER := 0;
BEGIN
open c_facture;
loop
FETCH c_facture into rec_facture;
exit when c_facture%notfound;
if fictifAvantBoucle = 0 then
dbms_output.put_line('Facture numéro: ' || rec_facture.i_ino || chr(10) || 'Date de facturation (Y/M/D): ' || rec_facture.i_date --section Facture
|| chr(10) || chr(10) || 'Vendu par ' || chr(10) || rec_facture.s_nom || chr(10) || 'Téléphone: ' || rec_facture.s_phone || chr(10) --section vendeur
|| 'Address: ' || rec_facture.s_address || chr(10)
|| 'Ville: ' || rec_facture.s_city || chr(10) || 'État: ' || rec_facture.s_state || chr(10) || 'ZIP: ' || rec_facture.s_zip
|| chr(10) || chr(10) || 'Facturé à ' || chr(10) || rec_facture.c_contact || chr(10) || 'Téléphone: ' || rec_facture.c_phone || chr(10) --section client
|| 'Address: ' || rec_facture.c_address
|| chr(10) || 'Ville: ' || rec_facture.c_city || chr(10) || 'État: ' || rec_facture.c_state || chr(10) || 'ZIP: ' || rec_facture.c_zip || chr(10)
|| chr(10) || '---------------------------------------------------------------------------------------------------------------------------' --section facture Article
|| chr(10) || 'Qty' || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || 'Article' || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9)
|| 'Prix unitaire' || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || 'Montant total' || chr(10)
|| '---------------------------------------------------------------------------------------------------------------------------');
fictifAvantBoucle := fictifAvantBoucle + 1;
end if;
dbms_output.put_line(rec_facture.d_qty || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || rec_facture.p_description || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9)
|| rec_facture.d_prix || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || chr(9) || rec_facture.d_prixTotal);
end loop;
EXCEPTION
WHEN no_data_found THEN
dbms_output.put_line('no data found');
END;
BEGIN
imprimeFacture();
END;

Change your output line to something like
DBMS_OUTPUT.PUT_LINE(LPAD(rec_facture.d_qty, 3)) || -- d_qty : 3 characters
RPAD(' ', 21) || -- blanks
RPAD(rec_facture.p_description, 29) || -- p_description : 29 chars
LPAD(rec_facture.d_prix, 13) || -- d_prix : 13 chars
RPAD(' ', 23) || -- blanks
LPAD(rec_facture.d_prixTotal, 13)); -- d_prixTotal : 13 chars

Related

Adding spaces to a piped concatenation

How do I change my select statement so that the following will return spaces between the concatenated columns?
The current query is similar to:
SELECT
address_line1 || address_line2 || address_line3 || address_line4 || city || state || county || province || country || zip as address
FROM
table
Many thanks
Just add space characters in between the fields:
SELECT
address_line1 || ' ' || address_line2 || ' ' || address_line3 || ' ' ||
address_line4 || ' ' || city || ' ' || state || ' ' || county || ' ' ||
province || ' ' || country || ' ' || zip AS address
FROM yourTable;

How do i remove duplicate address line in plsql

I have org_name, add_line1 , add_line2, add_line3 which i have put on different lines by using
(RTRIM(org_name) || CHR(32) || NVL2(RTRIM(org_name), CHR(32) || '\line' || CHR(32), '') ||
RTRIM(add_line1) || CHR(32) || NVL2(RTRIM(add_line1), CHR(32) || '\line' || CHR(32), '') ||
RTRIM(add_line2) || CHR(32) || NVL2(RTRIM(add_line2), CHR(32) || '\line' || CHR(32), '') ||
RTRIM(add_line3) || CHR(32) || NVL2(RTRIM(add_line3), CHR(32) || '\line' || CHR(32), '') || )AS "POSTAL_ADDRESS"
The problem is sometimes org_name is same as add_line1 meaning in the output I am getting the name twice on lines 1 and 2.
What I can't figure out is how to show name once if line output is same as line2 output.
Can someone please help me on this?
a case-insensitive and having no space problem comparison might be made by using regexp_like() and trim() functions together :
case when regexp_like(trim(org_name),trim(add_line1),'i')
then
org_name
else add_line1
end as org_name
or you may try within concatenation of POSTAL ADDRESS string as
select line_no, case when regexp_like(trim(org_name),trim(add_line1),'i') then
rtrim(org_name) || chr(32) || nvl2(rtrim(org_name), chr(32) || '\line' || chr(32), '')
else
rtrim(org_name) || chr(32) || nvl2(rtrim(org_name), chr(32) || '\line' || chr(32), '') ||
rtrim(add_line1)|| chr(32) || nvl2(rtrim(add_line1), chr(32)|| '\line' || chr(32), ''
)
end as "POSTAL_ADDRESS"
from tab
Demo
Using CASE (or DECODE), e.g.
case when org_name <> add_line1 then <value you want to return)
else null
end

regex for oracle "create procedure" definition

I need regex to capture full "create procedure" statement.
Here is one of examples, which I used for testing my regex:
CREATE OR REPLACE PROCEDURE sp_for_comp (P_VARNAME IN VARCHAR2, P_VALUE IN OUT NUMBER)
as
v_if_exists NUMBER(10,0);
BEGIN
SELECT COUNT(*) INTO v_if_exists FROM PKG_VAR WHERE VARIABLENAME = P_VARNAME;
IF v_if_exists > 0
THEN
begin
SELECT VALUE INTO P_VALUE FROM PKG_VAR WHERE VARIABLENAME = P_VARNAME;
EXCEPTION
WHEN OTHERS THEN
NULL;
end;
ELSE
begin
INSERT INTO PKG_VAR VALUES(P_VARNAME, P_VALUE);
EXCEPTION
WHEN OTHERS THEN
NULL;
end;
END IF;
END;
/
Current regex:
/CREATE\s+(OR\s+REPLACE\s+)?PROCEDURE\s+(\w+)\s*\(((?!.*\bEND\b\s*(\w+\s*)?\;\s*\/).*\s*)+.+/
As for my issue: I use QRegularExpression class and program failed when I run it on large files. Also, when I run it on small file - all works correctly.
After a lot of tests on online debuggers, like regexr.com, I could not find problem in regex.
How I should change it and where are may be problems?
Try something very simple like:
CREATE(\s+OR\s+REPLACE)\s+PROCEDURE.*?END;\s*/
It just looks for the CREATE OR REPLACE PROCEDURE at the start and then the end will be END; followed by / (indicating the end of the PL/SQL block in the SQL scope) on the next line with the minimal amount between.
(Note: You will probably want to use the ni regular expression match parameters to allow . to match the newline character and to do case-insensitive matches.)
Example:
CREATE TABLE script (value ) AS
SELECT 'CREATE OR REPLACE PROCEDURE sp_for_comp (P_VARNAME IN VARCHAR2, P_VALUE IN OUT NUMBER)' || CHR(10)
|| ' as' || CHR(10)
|| ' v_if_exists NUMBER(10,0);' || CHR(10)
|| 'BEGIN' || CHR(10)
|| ' SELECT COUNT(*) INTO v_if_exists FROM PKG_VAR WHERE VARIABLENAME = P_VARNAME;' || CHR(10)
|| ' IF v_if_exists > 0' || CHR(10)
|| ' THEN' || CHR(10)
|| ' begin' || CHR(10)
|| ' SELECT VALUE INTO P_VALUE FROM PKG_VAR WHERE VARIABLENAME = P_VARNAME;' || CHR(10)
|| ' EXCEPTION' || CHR(10)
|| ' WHEN OTHERS THEN' || CHR(10)
|| ' NULL;' || CHR(10)
|| ' end;' || CHR(10)
|| 'ELSE' || CHR(10)
|| ' begin' || CHR(10)
|| ' INSERT INTO PKG_VAR VALUES(P_VARNAME, P_VALUE);' || CHR(10)
|| ' EXCEPTION' || CHR(10)
|| ' WHEN OTHERS THEN' || CHR(10)
|| ' NULL;' || CHR(10)
|| ' end;' || CHR(10)
|| ' END IF;' || CHR(10)
|| 'END;' || CHR(10)
|| '/'
FROM DUAL;
SELECT COUNT(*)
FROM script
WHERE REGEXP_LIKE( value, '^CREATE(\s+OR\s+REPLACE)\s+PROCEDURE.*?END;\s*/$', 'n' );
Outputs:
COUNT(*)
--------
1

How to Select 2 Different Names from same table and display them on the Condition

I have this Query
SELECT NAME_NO
,(
SELECT FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE
FROM NAMES
WHERE NAME_NO = 1
) AS "NAME1: NAME, DOB, PHONE"
,(
SELECT FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE
FROM NAMES
WHERE NAME_NO = 2
) AS "NAME2: NAME, DOB, PHONE"
,
FROM NAMES;
I get this error:
01427. 00000 - "single-row subquery returns more than one row"
I need multiple records.
What is the best method to solve this?
Try this one:
SELECT NAME_NO, FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE AS "NAME1: NAME, DOB, PHONE"
FROM NAMES
UNION
SELECT FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE AS "NAME2: NAME, DOB, PHONE"
FROM NAMES
WHERE NAME_NO = 2
or this one:
WITH N1 AS (
SELECT NAME_NO,FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE AS "VAL"
FROM NAMES
WHERE NAME_NO = 1),
N2 AS (
SELECT FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE AS "VAL"
FROM NAMES
WHERE NAME_NO = 2)
SELECT
NAME_NO,VAL
FROM N1,N2;
You need to use PIVOT. Try this
Select A "NAME1: NAME, DOB, PHONE" , B "NAME2: NAME, DOB, PHONE" from (SELECT FNAME || ' ' || LNAME || ' ' || BIRTH_DT || ' ' || ' ' || PHONE N, NAME_NO
FROM NAMES)
Pivot
(Max(N) for NAME_NO in (1 as A, 2 as B)
);

PL/SQL: numeric or value error%s in loop

I have a function with a loop inside a loop and I'm getting 'numeric or value error'.
sendXML CLOB;
FOR p IN (
SELECT ID, NAME, GUID FROM products
WHERE ID = IN_PROJECT_ID
)
LOOP
if p.ID is not null and p.NAME is not null then
sendXML := sendXML || '<product type="product" id="' || p.ID|| '" name="' || p.NAME || '">';
FOR t IN (
SELECT
identifier ATTR_IDENTIFIER,
label ATTR_LABEL,
CASE type
WHEN UPPER('STRING') THEN TRIM(string_value)
WHEN UPPER('NUMBER') THEN TRIM(TO_CHAR(number_value))
ELSE '' END ATTR_VALUE
FROM products_data
WHERE
product_id = p.ID AND
identifier is not null
ORDER BY identifier
)
LOOP
sendXML := sendXML || '<attribute identifier="' || t.ATTR_IDENTIFIER || '" label="'|| t.ATTR_LABEL || '">' || t.ATTR_VALUE || '</attribute>';
END LOOP;
END IF;
END LOOP;
The error
ORA-06502: PL/SQL:numeric or value error ORA-06512: at "ASM.XXXX", line 85 06502
06502. 00000 - "PL/SQL: numeric or value error%s"
throws for the line:
sendXML := sendXML || '<product type="product" id="' || p.ID|| '" name="' || p.NAME || '">';
But I found out that if I delete the last
sendXML := sendXML || '<attribute identifier="' || t.ATTR_IDENTIFIER || '" label="'|| t.ATTR_LABEL || '">' || t.ATTR_VALUE || '</attribute>';
I'm not getting any error.
Wheres the problem?
SOLUTION:
p.ID is integer and must be char... TO_CHAR(p.ID) solved my problem!
sendXML := sendXML || '<product type="product" id="' || TO_CHAR(p.ID) ||
My guess is that the string becomes larger than the maximum for varchar2 in PL/SQL.
Try the following to append text to a clob:
dbms_lob.append(sendXML, to_clob('<product type="product" id="' || p.ID|| '" name="' || p.NAME || '">'));
and the second one:
dbms_lob.append(sendXML, to_clob('<attribute identifier="' || t.ATTR_IDENTIFIER || '" label="'|| t.ATTR_LABEL || '">' || t.ATTR_VALUE || '</attribute>'));
Use quote operator like
sendXML := sendXML || q'[<attribute identifier=']' || t.ATTR_IDENTIFIER || q'[' label=']'|| t.ATTR_LABEL || q'['>]' || t.ATTR_VALUE || q'[</attribute>]';
To escape quotes. See if error persists