Total Number and Total Value pl/sql - plsql

I made a query within a cursor that calculates the total number of cancellations, cancels or returned items and the total value. However, I cannot get the right value for the totals of the items that been cancelled, return or all cancelled
create or replace PROCEDURE NUM_OF_RET_CAN(PRAM_DATE IN DATE)
AS
CURSOR CUR2 IS
SELECT I.CONDITION, I.DEL_DATE, SUM(DE.QUANTITY) NUMBER_OF_PRO,
SUM(NVL(DE.QUANTITY,0) * NVL (P.COSTS,0)) TOTAL
FROM ITEMS I, DE_DETAILS DE, PARTS P
WHERE DE.PRO_NO = P.PRO_NO
AND I.ITEMS_NO = DE.ITEM_NO
AND TO_CHAR(I.DEL_DATE, 'mm-yyyy') = TO_CHAR(PRAM_DATE, 'mm-yyyy')
GROUP BY I.CONDITION, I.DEL_DATE;
CAL_CUR CUR2%ROWTYPE;
BEGIN
OPEN CUR2;
FETCH CUR2 INTO CAL_CUR;
IF VARCUR1.CONDITION ='CANCELL' THEN
DBMS_OUTPUT.PUT_LINE('CANCELLED: '||CAL_CUR.NUMBER_OF_PRO );
DBMS_OUTPUT.PUT_LINE('Total: '|| CAL_CUR.TOTAL);
ELSIF VARCUR1.CONDITION ='ORDER RETURNED' THEN
DBMS_OUTPUT.PUT_LINE('RETURNED : '||
CAL_CUR.NUMBER_OF_PRO);
DBMS_OUTPUT.PUT_LINE('Total : '|| CAL_CUR.TOTAL);
ELSIF VARCUR1.CONDITION = 'ALL ORDERS ARE CANCELLED!' THEN
DBMS_OUTPUT.PUT_LINE('ALL CANCELLATIONS : '||
CAL_CUR.NUMBER_OF_PRO );
DBMS_OUTPUT.PUT_LINE('Total : '|| CAL_CUR.TOTAL);
ELSE
DBMS_OUTPUT.PUT_LINE('No records for this month');
END IF;
CLOSE CUR2;
END NUM_OF_RET_CAN;
If I run the select Query without using the cursor or the procedure I get this result:
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
------------ ------------- ------------------- ---------
ALL ORDERS ARE CANCELLED! 12-JAN-16 4 99.96
ALL ORDERS ARE CANCELLED! 10-JAN-16 2 44.98
Expected Answer
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
------------ ------------- ------------------- ---------
ALL ORDERS ARE CANCELLED! JAN-16 6 144.94
Any help would be much appreciated

Sounds like you just need to group by month rather than day, eg:
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
A few notes:
You'll note that I have converted your old-style joins into ANSI join syntax.
You had aliased the items table as "pros" but elsewhere in the query, the alias "i" was referenced. I believe this is what the alias for the items table should have been, so I updated it accordingly.
I've converted your to_char(... 'mm-yyyy')s to trunc(... 'mm') as I believe that comparing columns in the same format as they're defined is more meaningful (leading to easier maintenance etc).
I'm not sure why you're getting the "not a group by expression" error, since it's working for me:
with items as (select 1 items_no, 'a' condition, sysdate -1 del_date from dual union all
select 2 items_no, 'a' condition, sysdate del_date from dual union all
select 3 items_no, 'a' condition, sysdate + 31 del_date from dual),
de_details as (select 1 item_no, 10 quantity, 1 pro_no from dual union all
select 2 item_no, 20 quantity, 2 pro_no from dual union all
select 3 item_no, 40 quantity, 1 pro_no from dual),
parts as (select 1 pro_no, 100 costs from dual union all
select 2 pro_no, 200 costs from dual)
----- end of mimicking your tables with data in them
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
--where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
CONDITION DEL_DATE NUMBER_OF_PRO TOTAL
--------- --------- ------------- ----------
a 01-JAN-16 30 5000
a 01-FEB-16 40 4000
Are you sure that you added the trunc(..., 'mm') to the colunn in both the select and group by colunn lists?
Here's how I'd write the procedure, assuming that I needed to loop through each of the rows returned by the query and display them via dbms_output:
create or replace procedure num_of_ret_can (pram_date in date)
as
cursor cur2 is
select i.condition,
trunc(i.del_date, 'mm') del_date,
sum(de.quantity) number_of_pro,
sum(nvl(de.quantity,0) * nvl (p.costs,0)) total
from items i
inner join de_details de on (i.items_no = de.item_no)
inner join parts p on (de.pro_no = p.pro_no)
where trunc(i.del_date, 'mm') = trunc(pram_date, 'mm')
group by i.condition,
trunc(i.del_date, 'mm');
v_counter number := 0;
begin
for cal_cur in cur2
loop
v_counter := v_counter + 1;
if cal_cur.condition ='CANCELL' then -- are you sure? Not CANCEL?
dbms_output.put_line('CANCELLED: '||cal_cur.number_of_pro );
dbms_output.put_line('Total: '|| cal_cur.total);
elsif cal_cur.condition ='ORDER RETURNED' then
dbms_output.put_line('RETURNED : '||cal_cur.number_of_pro);
dbms_output.put_line('Total : '||cal_cur.total);
elsif cal_cur.condition = 'ALL ORDERS ARE CANCELLED!' then
dbms_output.put_line('ALL CANCELLATIONS : '||cal_cur.number_of_pro );
dbms_output.put_line('Total : '||cal_cur.total);
end if;
end loop;
if v_counter = 0 then
dbms_output.put_line('No records for this month');
end if;
end num_of_ret_can;
/

Related

CASE in BETWEEN in WHERE

I need to put a CASE statement in my WHERE clause, and that CASE statement contains a BETWEEN. But, I'm unable to get this working:
SELECT ticker, trending_rank
FROM (SELECT a.ticker, t.trending_rank
FROM (SELECT ticker FROM template7_data WHERE TRUNC(date_inserted) = TRUNC(SYSDATE)
MINUS
SELECT ticker FROM template7_data WHERE TRUNC(SYSDATE) BETWEEN TRUNC(date_excluded) AND TRUNC(date_released)) a, trending_tickers t
WHERE a.ticker = t.ticker
AND CASE
WHEN category_id = 516 THEN trending_rank BETWEEN 1 AND 200
ELSE trending_rank BETWEEN 100 AND 300
END
ORDER BY trending_rank)
WHERE rownum <= 5;
Any help would be great.

substr instr length for loop

good morning guys i have a problem with code i work on Health Care and complain code must be checkbox but they ask for Report that contain the treatment code which is gonna appear in database like this 1:15:2:3 etc so i need to calculate each code separate
i have to count until i get ":" then i need to take the number which can be 1 or 2 digit then making inner join with the other table
can anyone help me to fix this function and the problem in the loop and get the number for each one
create or replace function hcc_get_tcd_codes (p_id in number )
return varchar2 is
x number := 0 ;
y number := 0 ;
z number ;
code1 number ;
code_name varchar2(15);
begin
for i in 0 .. x
loop
select length(t.tcd_codes ) into x from hcc_patient_sheet t where t.id = p_id ; --- (9)العدد كامل
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاو(3)ل
select instr(tcd_codes, ':')+1 + y into z from hcc_patient_sheet t where t.id = p_id ; --عدد الكود كامل +1
enter code here
i := x -y ;
select substr(t.tcd_codes,z, instr(tcd_codes, ':')-1) into code1
--,select substr(t.tcd_codes, 0, instr(tcd_codes, ':')-1) as code2
from Hcc_Patient_Sheet t
where t.id = 631 ;
select t.alt_name into code_name from hcc_complaint_codes t where t.code = code1 ;
select instr(tcd_codes, ':') into y from hcc_patient_sheet t where t.id = p_id ; ---- عدد الكود الاول
return code_name ;
end loop ;
end;
Often with frequent sounding string processing issues, a wheel has already been invented, and even packaged.
select * from table(apex_string.split('THIS:IS:GREAT',':'));
Partial SUBSTR doesn't seem to be the best option; I'd suggest you to split that colon-separated-values string into row as follows:
SQL> with test (col) as
2 (select '1:15:2:3' from dual)
3 select regexp_substr(col, '[^:]+', 1, level) one_value
4 from test
5 connect by level <= regexp_count(col, ':') + 1;
ONE_VALUE
--------------------------------
1
15
2
3
SQL>
and use such an option in your query; something like this:
select ...
into ...
from some_table t
where t.id in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
);
If it has to be row-by-row, use the above option as a source for the cursor FOR loop, as
for cur_r in (select regexp_substr(that_string, '[^:]+', 1, level) one_value
from dual
connect by level <= regexp_count(that_string, ':') + 1
)
loop
do_something_here
end loop;

Count duplicate numbers in postgres

i have quick question.
I would like to count rows with same number.
This is what i get:
So i have 4 rows, with same number(59 b) and in count column i get ones.
I need to get 4 instead of 1, becouse i have 4 rows with same number.
This is my sql:
SELECT (z.miasto ||' '|| z.ulica ||' '|| z.nr_dom) as adres, (z.sym ||z.sym_ul||' '|| z.nr_dom) as symbol, zd.status, zd.id_administrator, z.uwagi,
COUNT(*) as liczba_osob
FROM zgloszenia as z
LEFT JOIN zgl_dzialamy AS zd ON (z.sym ||z.sym_ul||' '|| z.nr_dom) = (zd.sym ||zd.sym_ul||' '|| zd.nr_budynku)
WHERE status < 5
group by adres, symbol, zd.id_administrator, z.uwagi, zd.status
Can somebody tell me what am I doing wrong?
The reason why COUNT doesnt work is because the grouped values cannot aggregate.
They appear to be distinct from each other (probably the blacked out value: z.uwagi).
What you can do is SELECTing the non-DISTINCT values together and COUNT those instead. You can join this VALUE to your table after once the COUNTing is done. Or you can aggregate this column to your table as an array or json object.
SELECT
(z.miasto ||' '|| z.ulica ||' '|| z.nr_dom) as adres,
(z.sym ||z.sym_ul||' '|| z.nr_dom) as symbol,
zd.status,
zd.id_administrator,
-- z.uwagi, -- VALUE IS DISTINCT
COUNT(*) as liczba_osob
FROM zgloszenia as z
LEFT JOIN zgl_dzialamy AS zd ON (z.sym ||z.sym_ul||' '|| z.nr_dom) = (zd.sym ||zd.sym_ul||' '|| zd.nr_budynku)
WHERE status < 5
group by
adres,
symbol,
zd.id_administrator,
-- z.uwagi,
zd.status

getting total number to specific patients in rdlc report

I have made an rdlc report of total number of patients in a day and it works fine. I have the total number of female male patients, but when the report binds it returns a total equal to the number of rows in my data.
For example if I have 20 rows in my report then below when I print the count it returns the count in 20 rows.
How can I get it to be in only 1 row?
This is the query I'm using:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON GO
ALTER PROCEDURE [dbo].[Test_test_test]-- '2013/08/02'
-- Add the parameters for the stored procedure here
-- Add the parameters for the stored procedure here
(#date VARCHAR(20))
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT ( CASE
WHEN OLD_NEW_PATIENT.OLD_NEW = 'new' THEN
PATIENT_REF_MASTER.PAT_ID
ELSE NULL
END ) AS 'new',
( CASE
WHEN OLD_NEW_PATIENT.OLD_NEW = 'old' THEN
PATIENT_REF_MASTER.PAT_ID
ELSE NULL
END ) AS 'old',
----------------------------------------
( CASE
WHEN GENDER_MASTER.NAME1 = 'Female' THEN GENDER_MASTER.NAME1
ELSE NULL
END ) AS
'Females',
( CASE
WHEN GENDER_MASTER.NAME1 = 'Male' THEN GENDER_MASTER.NAME1
ELSE NULL
END ) AS 'Males',
-------------------------------------
CONVERT(VARCHAR, PATIENT_REF_MASTER.CREATION_DATE, 105) AS
'creation_Date',
PATIENT_REF_MASTER.SR_NO AS 'sr_No',
PATIENT_MASTER.PAT_FNAME + ' '
+ PATIENT_MASTER.PAT_SNAME AS 'NAME',
DEPT_ID AS
'Dept_ID',
DEPT_MASTER.DEPT_NAME AS
'Dept_Name',
DOC_MASTER.DOC_ID AS
'Doc_Master',
DOC_MASTER.DOC_FNAME + ' '
+ DOC_MASTER.DOC_SNAME AS
'Doc_Name'
,
PATIENT_MASTER.PAT_ADDR
AS 'addr',
GENDER_MASTER.NAME1 AS
'Pat_Sex',
PATIENT_MASTER.AGE AS 'age',
(SELECT Count(PATIENT_REF_MASTER.SR_NO)
FROM PATIENT_REF_MASTER
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date) AS 'count',
(SELECT Count(PATIENT_MASTER.PAT_SEX)
FROM PATIENT_MASTER
LEFT JOIN PATIENT_REF_MASTER
ON PATIENT_REF_MASTER.PAT_ID =
PATIENT_MASTER.PAT_CODE
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date
AND PATIENT_MASTER.PAT_SEX = 2) AS
'F_count',
(SELECT Count(PATIENT_MASTER.PAT_SEX)
FROM PATIENT_MASTER
LEFT JOIN PATIENT_REF_MASTER
ON PATIENT_REF_MASTER.PAT_ID =
PATIENT_MASTER.PAT_CODE
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date
AND PATIENT_MASTER.PAT_SEX = 1) AS
'M_count'
FROM PATIENT_REF_MASTER
LEFT JOIN DBO.OLD_NEW_PATIENT
ON DBO.OLD_NEW_PATIENT.CODE = PATIENT_REF_MASTER.OLD_NEW
LEFT JOIN DBO.DEPT_MASTER
ON DEPT_MASTER.DEPT_CODE = PATIENT_REF_MASTER.DEPT_ID
LEFT JOIN PATIENT_MASTER
ON PATIENT_MASTER.PAT_CODE = PATIENT_REF_MASTER.PAT_ID
LEFT JOIN DOC_MASTER
ON DOC_MASTER.DOC_ID = PATIENT_REF_MASTER.DOC_ID
LEFT JOIN GENDER_MASTER
ON GENDER_MASTER.CODE = PATIENT_MASTER.PAT_SEX
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date
--MONTH(Patient_Ref_master.creation_Date)=#month and Dept_ID=#dept
ORDER BY PATIENT_REF_MASTER.SR_NO ASC
-- select Dept_Master.Dept_Name as 'Dept_Name',
-- count(Pat_ID) as 'Pat_ID'
--
-- from Patient_Ref_master
--left join dbo.Dept_Master on Dept_Master.Dept_code = Patient_Ref_master.Dept_ID
--where MONTH(Patient_Ref_master.creation_Date)=#month and Dept_ID=#dept
--group by Dept_Master.Dept_Name
END
I think you're trying to do to many things at once ;-)
The heart of your problem lies here:
SELECT Count(PATIENT_MASTER.PAT_SEX)
FROM PATIENT_MASTER
LEFT JOIN PATIENT_REF_MASTER
ON PATIENT_REF_MASTER.PAT_ID =
PATIENT_MASTER.PAT_CODE
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date
AND PATIENT_MASTER.PAT_SEX = 1
By using this query within your query, it will return the total in each and every row. This is also why you can get away with writing the query and not using the GROUP BY clause.
I suggest you do all the work in this query with the exception of the count, and then use another query outside of this one for the count.
A secondary problem is that in your query you're requesting several details about each row, but you want it to come back in one row. You have to decide what you want ;).
In order to get just the counts in one row, try something like this:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON GO
ALTER PROCEDURE [dbo].[Test_test_test]-- '2013/08/02'
-- Add the parameters for the stored procedure here
-- Add the parameters for the stored procedure here
(#date VARCHAR(20))
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT Count(*) count,
Sum(CASE
WHEN FEMALES IS NOT NULL THEN 1
ELSE 0
END) F_Count,
Sum(CASE
WHEN MALES IS NOT NULL THEN 1
ELSE 0
END) M_Count
FROM (SELECT ( CASE
WHEN OLD_NEW_PATIENT.OLD_NEW = 'new' THEN
PATIENT_REF_MASTER.PAT_ID
ELSE NULL
END ) AS
'new',
( CASE
WHEN OLD_NEW_PATIENT.OLD_NEW = 'old' THEN
PATIENT_REF_MASTER.PAT_ID
ELSE NULL
END ) AS
'old',
----------------------------------------
( CASE
WHEN GENDER_MASTER.NAME1 = 'Female' THEN
GENDER_MASTER.NAME1
ELSE NULL
END ) AS
'Females',
( CASE
WHEN GENDER_MASTER.NAME1 = 'Male' THEN
GENDER_MASTER.NAME1
ELSE NULL
END ) AS
'Males',
-------------------------------------
CONVERT(VARCHAR, PATIENT_REF_MASTER.CREATION_DATE, 105) AS
'creation_Date',
PATIENT_REF_MASTER.SR_NO AS
'sr_No',
PATIENT_MASTER.PAT_FNAME + ' '
+ PATIENT_MASTER.PAT_SNAME AS
'NAME'
,
DEPT_ID
AS 'Dept_ID',
DEPT_MASTER.DEPT_NAME AS
'Dept_Name',
DOC_MASTER.DOC_ID AS
'Doc_Master',
DOC_MASTER.DOC_FNAME + ' '
+ DOC_MASTER.DOC_SNAME AS
'Doc_Name',
PATIENT_MASTER.PAT_ADDR AS
'addr'
,
GENDER_MASTER.NAME1
AS 'Pat_Sex',
PATIENT_MASTER.AGE AS
'age'
FROM PATIENT_REF_MASTER
LEFT JOIN DBO.OLD_NEW_PATIENT
ON DBO.OLD_NEW_PATIENT.CODE =
PATIENT_REF_MASTER.OLD_NEW
LEFT JOIN DBO.DEPT_MASTER
ON DEPT_MASTER.DEPT_CODE =
PATIENT_REF_MASTER.DEPT_ID
LEFT JOIN PATIENT_MASTER
ON PATIENT_MASTER.PAT_CODE =
PATIENT_REF_MASTER.PAT_ID
LEFT JOIN DOC_MASTER
ON DOC_MASTER.DOC_ID = PATIENT_REF_MASTER.DOC_ID
LEFT JOIN GENDER_MASTER
ON GENDER_MASTER.CODE = PATIENT_MASTER.PAT_SEX
WHERE PATIENT_REF_MASTER.CREATION_DATE = #date
--MONTH(Patient_Ref_master.creation_Date)=#month and Dept_ID=#dept
)T
ORDER BY PATIENT_REF_MASTER.SR_NO ASC
END
I hope this helps, let me know if you need any more info.
Edit
Found a small mistake in the query I posted, the field names should have been FEMALES not FEMALE and MALES not MALE.
I also set up a scaled down example in SQL Fiddle. Take a look and tell me what you think.

Pl/SQL - oracle 9i - Manual Pivoting

We have a table which has three columns in it:
Customer_name, Age_range, Number_of_people.
1 1-5 10
1 5-10 15
We need to return all the number of people in different age ranges as rows of a single query. If we search for customer #1, the query should just return one row:
Header- Age Range (1-5) Age Range (5-10)
10 15
We needed to get all the results in a single row; When I query for customer 1, the result should be only number of people in a single row group by age_range.
What would be the best way to approach this?
You need to manually perform a pivot:
SELECT SUM(CASE WHEN age_range = '5-10'
THEN number_of_people
ELSE NULL END) AS nop5,
SUM(CASE WHEN age_range = '10-15'
THEN number_of_people
ELSE NULL END) AS nop10
FROM customers
WHERE customer_name = 1;
There are easy solutions with 10g and 11g using LISTGAGG, COLLECT, or other capabilities added after 9i but I believe that the following will work in 9i.
Source (http://www.williamrobertson.net/documents/one-row.html)
You will just need to replace deptno with customer_name and ename with Number_of_people
SELECT deptno,
LTRIM(SYS_CONNECT_BY_PATH(ename,','))
FROM ( SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS seq
FROM emp )
WHERE connect_by_isleaf = 1
CONNECT BY seq = PRIOR seq +1 AND deptno = PRIOR deptno
START WITH seq = 1;
DEPTNO CONCATENATED
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
This will create a stored FUNCTION which means you can access it at any time.
CREATE OR REPLACE FUNCTION number_of_people(p_customer_name VARCHAR2)
RETURN VARCHAR2
IS
v_number_of_people NUMBER;
v_result VARCHAR2(500);
CURSOR c1
IS
SELECT Number_of_people FROM the_table WHERE Customer_name = p_customer_name;
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO v_number_of_people;
EXIT WHEN c1%NOTFOUND;
v_result := v_result || v_number_of_people || ' ' || CHR(13);
END;
END;
To run it, use:
SELECT number_of_people(1) INTO dual;
Hope this helps, and please let me know if there are any errors, I didn't testrun the function myself.
Just do
select Number_of_people
from table
where Customer_name = 1
Are we missing some detail?

Resources