CREATE OR REPLACE TRIGGER CLIENTS_DISCOUNT
BEFORE INSERT OR UPDATE
OF DISCOUNT
ON CLIENTS
FOR EACH ROW
BEGIN
IF (NEW.ISACTIVE = 'N')
THEN RAISE_APPLICATION_ERROR
(-20001, 'CUSTOMER IS NOT ACTIVE')
END IF;
END;
Sample clients table:
CREATE TABLE clients (ClientID, ClientName, Discount, isActive, PrimarySiteID) AS
SELECT 1, '21st Century Fox', 5, 'Y', 1 FROM DUAL UNION ALL
SELECT 2, 'Erikson', 10, 'N', 2 FROM DUAL UNION ALL
SELECT 3, 'It Smart Group', 5, 'Y', 3 FROM DUAL UNION ALL
SELECT 4, 'UPC', 5, 'N', 4 FROM DUAL UNION ALL
SELECT 5, 'Telekom', 15, 'Y', 5 FROM DUAL UNION ALL
SELECT 6, 'ExxonMobil', 10, 'N', 6 FROM DUAL UNION ALL
SELECT 7, 'Biolife Grup', 20, 'Y', 7 FROM DUAL UNION ALL
SELECT 8, 'Apple Inc.', 0, 'N', 8 FROM DUAL UNION ALL
SELECT 9, 'AECOM', 5, 'Y', 9 FROM DUAL UNION ALL
SELECT 10, 'Metro', 10, 'N', 10 FROM DUAL;
I want to create a PL/SQL before insert or update trigger that restricts clients that are not active to getting their discount updated. I am not sure if I need to declare something.
I am not sure if I need to declare something.
No, you do not need the DECLARE keyword if you are not going to declare any variables.
A trigger has the syntax:
trigger_body ::=
The syntax for a PL/SQL block is:
Which demonstrates that the DECLARE is optional.
All you need to do is check IF the :NEW.isActive (or :OLD.isActive) equals N and if it does THEN use RAISE_APPLICATION_ERROR to generate a user-defined error and prevent the insert/update.
Related
have a query and test CASE that shows the number of full-time and part-time students. A full-time student is enrolled in at least 4 courses. A part-time student is enrolled in at least 1 course, but no more than 3.
Although the query appears to work it seems a bit verbose. I was wondering if there is a more succinct way to rewrite the query. In addition, I can would like to display the students first/last names with each row that meets the criteria
Perhaps with something like this?
, LISTAGG(
NVL2(s.student_id, s.last_name || ', ' || s.first_name, NULL),
'; '
) WITHIN GROUP (ORDER BY s.last_name, s.first_name) AS students
Below are my tables, data and query I would like to shorten if possible. Thanks to all who answer and for your expertise.
CREATE TABLE students(student_id, first_name, last_name) AS
SELECT 1, 'Faith', 'Aaron' FROM dual UNION ALL
SELECT 2, 'Lisa', 'Saladino' FROM dual UNION ALL
SELECT 3, 'Leslee', 'Altman' FROM dual UNION ALL
SELECT 4, 'Patty', 'Kern' FROM dual UNION ALL
SELECT 5, 'Beth', 'Cooper' FROM dual UNION ALL
SELECT 95, 'Zak', 'Despart' FROM dual UNION ALL
SELECT 96, 'Owen', 'Balbert' FROM dual UNION ALL
SELECT 97, 'Jack', 'Aprile' FROM dual UNION ALL
SELECT 98, 'Nicole', 'Kramer' FROM dual UNION ALL
SELECT 99, 'Jill', 'Coralnick' FROM dual;
CREATE TABLE student_courses (student_id,course_id) AS
SELECT 1, 1 FROM dual UNION ALL
SELECT 2, 1 FROM dual UNION ALL
SELECT 3, 1 FROM dual UNION ALL
SELECT 4, 1 FROM dual UNION ALL
SELECT 5, 1 FROM dual UNION ALL
SELECT 1, 2 FROM dual UNION ALL
SELECT 2, 2 FROM dual UNION ALL
SELECT 3, 2 FROM dual UNION ALL
SELECT 4, 2 FROM dual UNION ALL
SELECT 5, 2 FROM dual UNION ALL
SELECT 1, 3 FROM dual UNION ALL
SELECT 2, 3 FROM dual UNION ALL
SELECT 3, 3 FROM dual UNION ALL
SELECT 4, 3 FROM dual UNION ALL
SELECT 5, 3 FROM dual UNION ALL
SELECT 97, 1 FROM dual UNION ALL
SELECT 97, 3 FROM dual UNION ALL
SELECT 97, 5 FROM dual UNION ALL
SELECT 97, 6 FROM dual UNION ALL
SELECT 98, 3 FROM dual UNION ALL
SELECT 98, 4 FROM dual UNION ALL
SELECT 98, 5 FROM dual UNION ALL
SELECT 99, 2 FROM dual UNION ALL
SELECT 99, 4 FROM dual UNION ALL
SELECT 99, 5 FROM dual UNION ALL
SELECT 99, 6 FROM dual;
WITH enrolled_student_course_counts AS (
SELECT
s.student_id
, s.first_name
, s.last_name
, COUNT(sc.course_id) AS course_count
FROM students s
LEFT JOIN student_courses sc
ON s.student_id = sc.student_id
GROUP BY
s.student_id
, s.first_name
, s.last_name
HAVING COUNT(sc.course_id) > 0
)
, student_enrollment_statuses AS (
SELECT
student_id
, first_name
, last_name
, CASE WHEN course_count >= 4 THEN 'full-time'
WHEN course_count BETWEEN 1 AND 3 THEN 'part-time'
END AS student_enrollment_status
FROM enrolled_student_course_counts
)
SELECT
UPPER(student_enrollment_status) AS student_enrollment_status
, COUNT(student_enrollment_status) AS student_enrollment_status_count
FROM student_enrollment_statuses
GROUP BY student_enrollment_status;
As you only need the numbers (and not any other data), shorten the query so that it searches only the student_courses table:
SQL> with temp as
2 (select student_id,
3 count(course_id) cnt
4 from student_courses
5 group by student_id
6 )
7 select
8 sum(case when cnt < 4 then 1 else 0 end) part_time,
9 sum(case when cnt >= 4 then 1 else 0 end) full_time
10 from temp;
PART_TIME FULL_TIME
---------- ----------
6 2
SQL>
I try to use JSON_ARRAYAGG into select and get bug result with the same data
SELECT json_object(
'buy' VALUE JSON_ARRAYAGG(b.buysum),
'total' VALUE JSON_ARRAYAGG(b.totalsum)
)
FROM (
select *
from view_count_sum
ORDER BY date_rw DESC
FETCH FIRST 10 ROWS ONLY
) b
ORDER BY b.date_rw;
As a result i get JSON with 2 arrays which have decrease data order in first array and wrong order in second array
{"buy":[4168,4145,4130,4101,4068,4042,4008,3940,3900,3858],"total":[7778,7258,7333,7442,7546,7607,7642,7683,7718,7745]}
If I replace position JSON_ARRAYAGG in select I see right order for first array again and wrong order for second array
SELECT json_object(
'total' VALUE JSON_ARRAYAGG(b.totalsum),
'buy' VALUE JSON_ARRAYAGG(b.buysum)
)
FROM (
select *
from view_count_sum
ORDER BY date_rw DESC
FETCH FIRST 10 ROWS ONLY
) b
ORDER BY b.date_rw;
See result:
{"total":[7778,7745,7718,7683,7642,7607,7546,7442,7333,7258],"buy":[4168,3858,3900,3940,4008,4042,4068,4101,4130,4145]}
The order second and any other arrays is wrong. The first element is right but all other are reversed
Starting with some data where the expected order is easy to see:
CREATE TABLE view_count_sum (date_rw, buysum, totalsum) AS
SELECT 10, 1, 1 FROM DUAL UNION ALL
SELECT 9, 2, 2 FROM DUAL UNION ALL
SELECT 8, 3, 3 FROM DUAL UNION ALL
SELECT 7, 4, 4 FROM DUAL UNION ALL
SELECT 6, 5, 5 FROM DUAL UNION ALL
SELECT 5, 6, 6 FROM DUAL UNION ALL
SELECT 4, 7, 7 FROM DUAL UNION ALL
SELECT 3, 8, 8 FROM DUAL UNION ALL
SELECT 2, 9, 9 FROM DUAL UNION ALL
SELECT 1, 10, 10 FROM DUAL;
Then, if you do:
SELECT json_object(
'buy' VALUE JSON_ARRAYAGG(b.buysum),
'total' VALUE JSON_ARRAYAGG(b.totalsum)
) AS json
FROM (
select *
from view_count_sum
ORDER BY date_rw DESC
FETCH FIRST 10 ROWS ONLY
) b
ORDER BY b.date_rw;
Then the output is:
JSON
{"buy":[1,2,3,4,5,6,7,8,9,10],"total":[1,10,9,8,7,6,5,4,3,2]}
Instead, if you add the ORDER BY clause into the aggregation functions:
SELECT json_object(
'buy' VALUE JSON_ARRAYAGG(b.buysum ORDER BY b.date_RW DESC),
'total' VALUE JSON_ARRAYAGG(b.totalsum ORDER BY b.date_RW DESC)
) AS json
FROM (
select *
from view_count_sum
ORDER BY date_rw DESC
FETCH FIRST 10 ROWS ONLY
) b;
Then the output is:
JSON
{"buy":[1,2,3,4,5,6,7,8,9,10],"total":[1,2,3,4,5,6,7,8,9,10]}
db<>fiddle for Oracle 18
Hi all I have requirement to pick records using dynamic pivoting in Oracle. I have done with my query which is working fine using "antonsPivoting" https://technology.amis.nl/2006/05/24/dynamic-sql-pivoting-stealing-antons-thunder/.
When i add the query in procedure it gives error: ORA-22905: cannot access rows from a non-nested table item.
Sample table script:
CREATE TABLE DEPARTMENT(DEPT_ID NUMBER PRIMARY KEY, DEPT_NAME VARCHAR2(25))
CREATE TABLE EMPLOYEE(EMP_ID NUMBER, EMP_NAME VARCHAR(100), DEPT_ID NUMBER , FOREIGN KEY(DEPT_ID) REFERENCES DEPARTMENT(DEPT_ID))
INSERT INTO DEPARTMENT(DEPT_ID, DEPT_NAME)
SELECT 1, 'HR' FROM DUAL
UNION ALL SELECT 2, 'OPS' FROM DUAL
UNION ALL SELECT 3, 'MKT' FROM DUAL
UNION ALL SELECT 4, 'FIN' FROM DUAL
UNION ALL SELECT 5, 'IT' FROM DUAL
UNION ALL SELECT 6, 'SERV' FROM DUAL
COMMIT;
INSERT INTO EMPLOYEE(EMP_ID, EMP_NAME, DEPT_ID)
SELECT 1, 'A', 1 FROM DUAL
UNION ALL SELECT 1, 'A', 1 FROM DUAL
UNION ALL SELECT 2, 'B', 1 FROM DUAL
UNION ALL SELECT 3, 'C', 2 FROM DUAL
UNION ALL SELECT 4, 'D', 3 FROM DUAL
UNION ALL SELECT 5, 'E', 3 FROM DUAL
UNION ALL SELECT 6, 'F', 4 FROM DUAL
UNION ALL SELECT 7, 'G', 4 FROM DUAL
UNION ALL SELECT 8, 'H', 4 FROM DUAL
UNION ALL SELECT 9, 'I', 5 FROM DUAL
UNION ALL SELECT 10, 'J', 5 FROM DUAL
UNION ALL SELECT 11, 'K', 1 FROM DUAL
UNION ALL SELECT 12, 'L', 1 FROM DUAL
COMMIT;
sample query script working fine:
SELECT D.DEPT_NAME, COUNT(E.EMP_ID) TOTAL_EMP
FROM DEPARTMENT D
LEFT JOIN EMPLOYEE E ON D.DEPT_ID= E.DEPT_ID
GROUP BY D.DEPT_NAME
;
Dynamic pivoting example working fine:
select * from table( pivot( '
SELECT D.DEPT_NAME, COUNT(E.EMP_ID) TOTAL_EMP
FROM DEPARTMENT D
LEFT JOIN EMPLOYEE E ON D.DEPT_ID= E.DEPT_ID
GROUP BY D.DEPT_NAME' ) )
;
adding in procedure which gives error:
CREATE OR REPLACE PROCEDURE GET_EMPLOYEE (P_RESULT OUT SYS_REFCURSOR)
IS
BEGIN
OPEN P_RESULT FOR
select * from table( pivot( '
SELECT D.DEPT_NAME, COUNT(E.EMP_ID) TOTAL_EMP
FROM DEPARTMENT D
LEFT JOIN EMPLOYEE E ON D.DEPT_ID= E.DEPT_ID
GROUP BY D.DEPT_NAME' ) )
;
END
;
Have you created the Pivot function ?
Please go through below link where this is already answered.
Link
I'm writing a procedure that have to replace a set of special characters with another set of them that are accepted to an application system. How can I re-write better the following statement that I'm using in the procedure?
select replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace('%BICI* "(MOTO), |X PLAY? 4G: RED&WHITE& \/<DIRETTA>','(','-'),'%','perc'),'?','.'),'|','-'),':',';'),',','.'),'<','-'),'>','-'),'&','and'),'\','-'),'/','-'),'"','-'),')','-'),'*','-')
from dual;
I can't use a recursive procedure.
Any suggestions?
Thanks!
Ilaria
This is an interesting one. Here's a working example based on Florin's example:
with trans_tbl(id, symbol, txt) as (
select 1, '(', '-' from dual union
select 2, '%', 'perc' from dual union
select 3, '?', '.' from dual union
select 4, '|', '-' from dual union
select 5, ':', ';' from dual union
select 6, ',', '.' from dual union
select 7, '<', '-' from dual union
select 8, '>', '-' from dual union
select 9, '&', 'and' from dual union
select 10, '\', '-' from dual union
select 11, '/', '-' from dual union
select 12, '"', '-' from dual union
select 13, ')', '-' from dual union
select 14, '*', '-' from dual
),
data_tbl(str) as (
select '%BICI* "(MOTO), |X PLAY? 4G: RED&WHITE& \/<DIRETTA>' from dual
),
working_tbl(str, id) as (
SELECT str, 0 id
FROM data_tbl
UNION ALL
SELECT replace(working_tbl.str,symbol,txt), trans_tbl.id
FROM working_tbl
JOIN trans_tbl
ON working_tbl.id = trans_tbl.id - 1
)
--select str, id from working_tbl;
SELECT str
from working_tbl
where id = (select max(id)
from trans_tbl);
STR
----------------------------------------------------------
percBICI- --MOTO-. -X PLAY. 4G; REDandWHITEand ---DIRETTA-
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Is it possible to and can someone please give me a good example of selecting in one query a result set that returns counts for demographics or other things group by a certain grouping? That really sound cryptic so I am going to add an example output of what I am trying to communicate. I want a result set like:
So for each class a count of fields that are populated for Gender, a count of Male, a count of Female, a count of how many of race that are populated and so forth.
So something like
Select curricul.class,count(stu.gender),count(stu.race),count(stu.eth)
from curricul,stu
group by class
pivot( count(gender) for gender in (male, female)
You could simply use:
with curricul as
(select 1 classid, 'Math' class from dual union all
select 2, 'Literature' from dual
)
,
student as
( select 1 id, 1 classid, 'male' gender, 1 race, 1 eth from dual union all
select 2, 1, 'female', 1, 2 from dual union all
select 3, 1, 'male' , 3, 1 from dual union all
select 4, 1, 'male' , 5, 7 from dual union all
select 5, 1, 'female', 4, 8 from dual union all
select 6, 1, 'male' , 1, 6 from dual union all
select 7, 2, 'female', 3, 4 from dual union all
select 8, 2, 'female', 1, 1 from dual union all
select 9, 2, 'female', 7, 9 from dual union all
select 10, 2, 'male' , 9, 1 from dual union all
select 11, 2, 'female', 8, 1 from dual
)
select s.classid, curricul.class
,count(s.gender) as count_gender
,sum(case when gender = 'male' then 1 else 0 end) as count_male
,sum(case when gender = 'female' then 1 else 0 end) as count_female
,count(s.race) as count_race
,count(s.eth) as count_ethnicity
from student s
inner join curricul
on s.classid = curricul.classid
group by s.classid, curricul.class ;