To me it looks much like you're asking only the registered users, as the SELECT
acting as the basis for the view is:
SELECT
[...]
FROM usr_t_user_reg
Thus having "some users who are not registered yet and they are not displayed in the output" is what should be expected.
Having something like this would show the not (yet) registered users:
SELECT
u.username "User",
r.db_instance "Instance",
NVL(r.db_instance,'not registered yet') "Status"
FROM
SYS.dba_users u LEFT OUTER JOIN usr_t_user_reg r ON u.username = r.username;
That will, however, not give those users that are still in the "registered" table but are not anymore DB users, for that you could use the parallel:
SELECT
r.username "User",
r.db_instance "Instance",
CASE NVL(u.username,'X') WHEN 'X' THEN 'not a user anymore' ELSE 'OK' END "Status"
FROM SYS.dba_users u RIGHT OUTER JOIN usr_t_user_reg r ON u.username = r.username;
The SQL above is probably possible to combine nicely, and is likely to be sub-optimal, but it did work on quick testing...
Edit:
Full outer join version combining the two queries above:
SELECT
NVL(r.username, u.username) "User",
r.db_instance "Instance",
CASE NVL(u.username,'X') WHEN 'X' THEN 'not a user anymore' ELSE
CASE NVL(r.db_instance,'X') WHEN 'X' THEN 'not registered' ELSE 'OK' END
END "Status"
FROM SYS.dba_users u FULL OUTER JOIN usr_t_user_reg r ON u.username = r.username;
Edit 2:
A version providing also the name of the instance(s) the user is not registered, the name of the instance(s) the non-existent user is registered to, and filtering out all of the cases where status is OK:
SELECT *
FROM (
WITH t1 AS (
SELECT
u.username,
i.db_instance
FROM SYS.dba_users u, ( SELECT DISTINCT db_instance FROM usr_t_user_reg ) i
)
SELECT
t1.username "User",
t1.db_instance "Instance",
CASE NVL(r.db_instance, 'X') WHEN 'X' THEN 'not registered' ELSE 'OK' END "Status"
FROM t1 LEFT OUTER JOIN usr_t_user_reg r ON t1.username = r.username AND t1.db_instance = NVL(r.db_instance, t1.db_instance)
union
SELECT
r.username "User",
r.db_instance "Instance",
CASE NVL(u.username,'X') WHEN 'X' THEN 'not a user anymore' ELSE 'OK' END "Status"
FROM SYS.dba_users u RIGHT OUTER JOIN usr_t_user_reg r ON u.username = r.username
)
WHERE "Status"!='OK';
It starts getting uglier and even less optimal, but again that did work on the test setup.
You need to avoid catching and reraising errors with a user defined error number. That will only make it harder to see where the error is happening. You should also avoid using explicit cursors and try using PL/SQL collections. As long as you are using 9i or above PL/SQL collections are the better way to go. You should probably have an index on transdetail
as follows:
CREATE UNIQUE INDEX transdetail_idx1
ON transdetail ( transtype, transdate, sr_cd, quantity);
This will greatly reduce the number of rows that Oracle needs to look at. It will do a range scan of the transdate
column for each of the transtype
values that you are searching for, plus the index has all of the columns that you want. Hence Oracle won't need to look at the index, then look at the table.
-- Let unhandled exceptions remain unhandled
-- EXCEPTION
-- This is a terrible example of error handling, don't use it
-- WHEN OTHERS THEN
-- raise_application_error(-20001,'An error was encountered - '||SQLCODE||'
-- -ERROR- '||SQLERRM);
-- END;
-- /
CREATE OR REPLACE PROCEDURE TEST_RECPT_0705
AS
TYPE transdetail_rec IS RECORD (
sr_cd transdetail.sr_cd%TYPE,
transdate transdetail.transdate%TYPE,
quantity transdetail.quantity%TYPE );
TYPE transdetail_type IS TABLE OF transdetail_rec
INDEX BY PLS_INTEGER;
transdetail_tab transdetail_type;
BEGIN
SELECT sr_cd, to_char(trunc(transdate,'mm'),'YYYYMM') Month, sum(quantity)Receipt
BULK COLLECT INTO transdetail_tab
FROM transdetail
WHERE transtype IN('STKREC','RP','RECADJ','SRET')
AND trunc(transdate,'mm') BETWEEN '01-April-2013' AND '31-March-2014'
GROUP BY trunc(transdate,'mm'),sr_cd;
FORALL i IN transdetail_tab.FIRST..transdetail_tab.LAST
UPDATE transdetail
SET receipt = transdetail_tab(i).RECEIPT
WHERE sr_cd = transdetail_tab(i).SR_CD
AND yyyymm = transdetail_tab(i).MONTH;
SELECT sr_cd, to_char(trunc(transdate,'mm'),'YYYYMM') Month, sum(quantity) Issue
FROM transdetail
WHERE transtype IN('SINV','IP','STA','ISSADJ','PURRET')
AND trunc(transdate,'mm') BETWEEN '01-April-2013' AND '31-March-2014'
GROUP BY trunc(transdate,'mm'), sr_cd;
FORALL i IN transdetail_tab.FIRST..transdetail_tab.LAST
UPDATE transdetail
SET receipt = transdetail_tab(i).RECEIPT
WHERE sr_cd = transdetail_tab(i).SR_CD
AND yyyymm = transdetail_tab(i).MONTH;
COMMIT;
END;
/
Best Answer
A CASE expression can only return a value, not a fragment of a query.
In order to parametrise which column should receive the value passed as an argument, you could try this approach:
I slightly simplified the logic, because according to your CASE expression, you want to update
FIRST_NAME
both whenTARGET_COL
is 1 and when it is anything other than 2. But the second condition actually covers the first one. So we can simplify the logic to this: ifTARGET_COL
is two, you want to updateLAST_NAME
, otherwise you want to updateFIRST_NAME
.So how does the above query work? If
TARGET_COL
is 2, thenFIRST_NAME
is updated toFIRST_NAME
, i.e. to the same value it already has. This way it remains unchanged. In contrast,LAST_NAME
in this case is set toUPDATED_VALUE
. If, however,TARGET_COL
is not 2 (but e.g. 1), thenFIRST_NAME
getsUPDATED_VALUE
, whileLAST_NAME
is set toLAST_NAME
– in other words, remains unchanged.