What code is needed to conditionally provide a value to a field in a beforeinsert trigger? - sql-server

I need to store a string value in a field in a table, specifically in its Subcategory VarChar(50) column.
The value of Subcategory prior to this post processing is either 0 or 1; I need to change that to a more human-friendly value.
I haven't created a database trigger in decades and need some help with the code. This is my pseudo SQL (a hodgepodge of SQL and VB):
CREATE OR REPLACE TRIGGER tr_CustomerCategoryLog_BeforeInsert
BEFORE INSERT ON CustomerCategoryLog FOR EACH ROW
DECLARE _Category = :new.Category;
DECLARE _Subcategory = :new.Subcategory;
BEGIN
If _Category = "New"
If _Subcategory = 0
:new.Subcategory := 'New';
End If
Else If _Subcategory = 1
:new.Subcategory := 'Assumed';
End If
End If
If _Category = "Existing"
If _Subcategory = 0
:new.Subcategory := 'Existing';
End If
Else If _Subcategory = 1
:new.Subcategory := 'Organic'
End If
End If
Return "Unknown"
End Function
END;
If the logic isn't clear, in semi-plain English it is:
If the value of the Category field is "New", set the Subcategory field value also to "New" if the value of Subcategory is currently 0; otherwise, set it to "Assumed"
If the value of the Category field is "Existing", set the Subcategory field value also to "Existing" if the value of Subcategory is currently 0; otherwise, set it to "Organic"
Maybe I need to give Steely Dan's album "Trigger Logic" a listen.
UPDATE
I think the answer will work, but it's not complete enough for me.
Since I apparently have Oracle code mixed up in the pseudoSQL above, what would the complete code need to look like (to create a BeforeInsert trigger on the CustomerCategoryLog table)?
Is this more like it:
CREATE TRIGGER tr_CustomerCategoryLog_BeforeInsert
ON CustomerCategoryLog
INSTEAD OF INSERT
AS
BEGIN
SELECT
CASE
WHEN #Category = 'New'
THEN CHOOSE(#Subcategory + 1, 'New', 'Assumed')
WHEN #Category = 'Existing'
THEN CHOOSE(#Subcategory + 1, 'Existing', 'Organic')
ELSE 'Unknown'
END
END
?

I tend to avoid triggers (perhaps a character flaw... I also don't like mashed potatoes), but the following illustration could simplify your logic
Declare #Category varchar(50) = 'Existing'
Declare #Subcategory int = 1 -- works if BIT
Select case when #Category = 'New' then choose(#Subcategory+1,'New','Assumed')
when #Category = 'Existing' then choose(#Subcategory+1,'Existing','Organic')
else 'Unknown' end
Returns
Organic

Related

Creating function in oracle

I am trying to create a function that change the day of a football league; if the match is fixed on saturday then the function update the match day to be the previuos friday, and if the match is fixed on sunday the function update the match date to be on monday. Also the function will show how many rows have been update.
The table I use is as follow:
CREATE TABLE "183400_Matches_Details" (
"183400_Stadiums_id" INTEGER NOT NULL,
"183400_Teams_id" INTEGER NOT NULL,
"183400_Teams_id1" INTEGER NOT NULL,
"183400:Referees_id" INTEGER NOT NULL,
"183400_Matches_number" INTEGER NOT NULL,
"date" DATE NOT NULL,
result VARCHAR2(5) NOT NULL
);
I tried the following statements to build the function, but it always gives me an error:
create or replace function updateDay (
v_number "183400_Matches_Details"."183400_Matches_number"%type)
return date
as
v_fecha "183400_Matches_Details"."date"%type;
begin
SELECT TO_CHAR("date", 'DAY', 'NLS_DATE_LANGUAGE=ENGLISH') as day1 into v_fecha FROM
"183400_Matches_Details"
where "183400_Matches_number" = v_number;
if day1 = 'SATURDAY' then
update "183400_Matches_Details"
set "date" = "date"-1
where "183400_Matches_number" = v_number;
elsif day1 = 'SUNDAY' then
update "183400_Matches_Details"
set "date" = "date"+1
where "183400_Matches_number" = v_number;
end if;
return SQL%ROWCOUNT;
end;
/
select * from "183400_Matches_Details"
DECLARE
v_number "183400_Matches_Details"."183400_Matches_number"%type := &number;
v_total_filas number(8);
BEGIN
v_total_filas := actualizaPrecioCoche(v_number);
DBMS_OUTPUT.put_line('There are ' || v_total_filas || ' updated rows');
END;
/
Any ideas to make it run correctly?=)
I changed your function as it should be. Try below.
CREATE TABLE "183400_Matches_Details"
(
"183400_Stadiums_id" INTEGER NOT NULL,
"183400_Teams_id" INTEGER NOT NULL,
"183400_Teams_id1" INTEGER NOT NULL,
"183400:Referees_id" INTEGER NOT NULL,
"183400_Matches_number" INTEGER NOT NULL,
"datee" DATE NOT NULL,
RESULT VARCHAR2 (5) NOT NULL
);
CREATE OR REPLACE FUNCTION updateDay (
v_number "183400_Matches_Details"."183400_Matches_number"%TYPE)
RETURN DATE
AS
v_fecha "183400_Matches_Details"."datee"%TYPE;
sql_qry VARCHAR2 (400 CHAR);
BEGIN
sql_qry :=
'SELECT TO_CHAR(datee, ''DAY'', ''NLS_DATE_LANGUAGE=ENGLISH'') where "183400_Matches_number"='
|| v_number;
EXECUTE IMMEDIATE sql_qry INTO v_fecha;
IF v_fecha = 'SATURDAY'
THEN
UPDATE "183400_Matches_Details"
SET "datee" = "datee" - 1
WHERE "183400_Matches_number" = v_number;
ELSIF v_fecha = 'SUNDAY'
THEN
UPDATE "183400_Matches_Details"
SET "datee" = "datee" + 1
WHERE "183400_Matches_number" = v_number;
END IF;
RETURN to_date('19000101','yyyymmdd') ;
END;
/
After a second look I realized what your asking is actually quite simple: Given a date that is Sat update it to Fri, and that is Sun update to Mon. This can actually be done in a single SQL statement.
I changed it from a function to a procedure as the purpose is to Update the database, and return the number of rows processed. But as a function it makes the purpose to get the row count and updating the database as a side effect. Names and types (IMHO) should always reflect the purpose of the routine. I did 'return' the row count as an OUT parameter - it being an informational side effect. See fiddle for full example.
create or replace
procedure reschedule_sat_sun_match_details(
p_match_number in "183400_Matches_Details"."183400_Matches_number"%type
, p_rows_updated out number)
as
begin
update "183400_Matches_Details"
set "date" = case to_char("date", 'dy')
when 'sat' then "date"-1 -- Sat update to Fri
when 'sun' then "date"+1 -- Sun update to Mon
end
where to_char("date", 'dy') in ('sat','sun')
and "183400_Matches_number" = p_match_number;
p_rows_updated := sql%rowcount;
end reschedule_sat_sun_match_details;
For day of week values I used the format 'dy' rather than 'day'. The difference being 'dy' returns day name abbreviations with a constant length without padding, while 'day' pads the returned values to the length of the longest day name (to get constant length) thus "sunday" is returned as "sunday " to match the length of "wednesday".
A couple other suggestions. Avoid Mixed Case name and names beginning with numbers. These require double quoting (") on every reference. This becomes a pain to just write and your queries much harder to read and understand. a table name Matches_Details_183400 the exact same information without requiring the quotes. (Yes Oracle will make it upper case in messages it it issues but you can still write it in mixed case if you wish - it will still be the same name.) It gives you no benefit but a lot of pain.
As #hotfix mentioned do not use reserved or keywords as object names. Oracle has documented such words and reserves the right to enforce a specific meaning whenever they choose. If/When they do makes an almost untraceable bug to find.

Oracle function re-write in SQL-Server

I have an Oracle function that needs to be converted to SQL-Server function
This is the Oracle Function:
FUNCTION check_education(in_crs_code IN VARCHAR2)
RETURN BOOLEAN IS
v_bool BOOLEAN := FALSE;
v_dummy VARCHAR2(1);
CURSOR find_education IS
SELECT 'x'
FROM KU_LIBRARY_EDUCATION_EXTLOAN
WHERE UPPER(course_code) = UPPER(in_crs_code) AND in_use = 'Y';
BEGIN
OPEN find_education;
FETCH find_education INTO v_dummy;
IF find_education%FOUND THEN
v_bool := TRUE;
ELSE
v_bool := FALSE;
END IF;
CLOSE find_education;
RETURN (v_bool);
END check_education;
This is what I have written in SQL-Server to replicate Oracle function:
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000))
RETURNS BIT AS
BEGIN
DECLARE #v_bool BIT = 0;
DECLARE #v_dummy VARCHAR(1);
DECLARE find_education CURSOR LOCAL FOR
SELECT 'x'
FROM [dbo].[KU_LIBRARY_EDUCATION_EXTLOAN]
WHERE UPPER(course_code) = UPPER(#in_crs_code)
AND in_use = 'Y';
OPEN find_education;
FETCH find_education INTO #v_dummy;
IF ##CURSOR_ROWS >1 BEGIN
SET #v_bool = 1;
END
ELSE BEGIN
SET #v_bool = 0;
END
CLOSE find_education;
DEALLOCATE find_education;
RETURN (#v_bool);
END;
I would expect the SQL server function to return 1 if the cursor returns 'x' but i'm getting 0. Anu help will be appreciated.
I would suggest using an inline table valued function instead of a scalar function. To make sure this is an inline table valued function it MUST be a single select statement. This means there can't be loops and other stuff. Fortunately this query does not actually need any loops. A simple count will return the number of rows. And any value other than 0 when converted to a bit will always be 1.
CREATE FUNCTION [dbo].[check_education]
(
#in_crs_code VARCHAR(4000)
) RETURNS table as return
SELECT CourseExists = convert(bit, count(*))
FROM [dbo].[KU_LIBRARY_EDUCATION_EXTLOAN]
WHERE UPPER(course_code) = UPPER(#in_crs_code)
AND in_use = 'Y';
This is a mere EXISTS thing, so we could try
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000)) RETURNS BIT AS
BEGIN
RETURN EXISTS ( <query> )
END;
But as far as I know, SQL Server doesn't accept this (though I cannot say why not - maybe it's because of their lack of a real boolean; Oracle doesn't accept it, because EXISTS is no keyword in their PL/SQL programming language).
So we'd use IF/ THEN/ ELSE:
CREATE FUNCTION [dbo].[check_education](#in_crs_code VARCHAR(4000)) RETURNS BIT AS
BEGIN
IF EXISTS
(
SELECT 'x'
FROM ku_library_education_extloan
WHERE UPPER(course_code) = UPPER(in_crs_code) AND in_use = 'Y'
)
RETURN 1
ELSE
RETURN 0
END
END;
There may be errors, because I've never coded a stored procedure in T-SQL, but anyway, you get the idea.

SQL Server trigger for changing value of column of inserted row according to delta from other table after insert?

I have 2 tables in my SQL Server database, for example [Camera] and [CameraData]. How to write a trigger which will change value in [CameraData] after row is inserted into [CameraData] due to delta in [Camera].
For example we have 2 cameras in [Camera]:
Camera 1 with {id} = 1 and {delta} = null
Camera 2 with {id} = 2 and {delta} = 3
So when we have automated insert into table [CameraData], f.e. :
Id_camera = 2, angle = 30, Changed = null
In that case we need to check either we have delta in [Camera] on camera 2 and if that's true we need to modify insert to:
Id_camera = 2, angle = 33 (angle + Camera.Delta), Changed = True
Update 1
According to comment [3] is the column in table [CameraData] where angle is placed
CREATE TRIGGER Delta_Angle
ON CameraData
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
UPDATE CameraData
SET DeltaFlag = 1, [3] = inserted.[3] + i.DeltaAngle
FROM CameraData h
INNER JOIN Camera i ON h.ID_Camera = i.ID_Camera
WHERE i.DeltaAngle != ''
END
This is very much a stab in the dark, as your sample SQL isn't at all representative of the data your describe in your question, however, maybe something like:
CREATE TRIGGER Delta_Angle ON CameraData
AFTER INSERT AS
BEGIN
SET NOCOUNT ON;
UPDATE C
SET Angle = C.Angle + i.delta
FROM Camera
JOIN inserted i ON C.CameraID = i.CameraID;
END
Notice that I refer to inserted; your trigger wasn't. Also, I'm not sure about your clause i.DeltaAngle != ''. Considering that DeltaAngle appears to be an int, it can never have a value of '' (however, '' would be implicitly converted to the value 0).
If this doesn't help, I (again) suggest you read Sean's link and update your post accordingly.

How to write these kind of functions in solr data config.xml

CREATE OR REPLACE FUNCTION page(IN i_app name character varying, IN i_photo_id big int, IN i_page integer, IN i_member_id big int, OUT o_similar_page_name character varying, OUT o_similar_page_id big int, OUT o_similar_photo_id big int[])
DECLARE
v_limit INTEGER := 4;
v_offset INTEGER;
BEGIN
SET SEARCH_PATH = '';
v_start_time = DAYTIME();
i_app name = UPPER(i_app name);
IF i_app name <> 'DD' THEN
RAISE EXCEPTION 'Enter Valid Application Name';
END IF;
IF i_page = 1 THEN
v_offset := 0;
ELSE
v_offset := i_page * v_limit - v_limit;
END IF;
Please help me.
Answer
No.
Reason
Its not actually the purpose of SOLR. Functions has to be written in the DB level and the data that is retrieved out of query will be stored in SOLR for fast retrieval.
ALTERNATIVE SOLUTION
You can create the function and call it in the select statement to index the data into SOLR.
Note : Final results fetched out of functions can be stored in the SOLR.
Example:
CREATE FUNCTION CustomerLevel(p_creditLimit double) RETURNS VARCHAR(10)
DETERMINISTIC
BEGIN
DECLARE lvl varchar(10);
IF p_creditLimit > 50000 THEN
SET lvl = 'PLATINUM';
ELSEIF (p_creditLimit <= 50000 AND p_creditLimit >= 10000) THEN
SET lvl = 'GOLD';
ELSEIF p_creditLimit < 10000 THEN
SET lvl = 'SILVER';
END IF;
RETURN (lvl);
END
Query to used in SOLR for Indexing
SELECT CustomerLevel(123123123) as CustomerLevel from CustomerRating;

Oracle Triggers Update at Another Table

I am trying to create a trigger in Oracle. I know sql but i have never created trigger before. I have this code:
create or replace trigger "PASSENGER_BOOKING_T1"
AFTER
insert on "PASSENGER_BOOKING"
for each row
begin
IF (:NEW.CLASS_TYPE == 'ECO')
SELECT F.AVL_SEATS_ECOCLASS,F.FLIGHT_ID INTO SEAT, FLIGHT_INFO
FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F
WHERE B.JOURNEY_ID = J.JOURNEY_ID and F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (SEAT-1)
WHERE FLIGHT_ID = FLIGHT_INFO;
END IF;
end;​
This trigger fires when there is an insert in Passenger_Booking table. And seating capacity is reduced by one (which is at different table).
Select query should be alright but there is something wrong in somewhere.
Could anyone suggest anything?
I changed the body part to this but still having issues:
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS =
(SELECT F.AVL_SEATS_ECOCLASS FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F WHERE B.JOURNEY_ID = J.JOURNEY_ID and F.FLIGHT_ID = J.FLIGHT_ID;
);
An IF statement needs a THEN
In PL/SQL, you use an = to test for equality, not ==
You need to declare the variables that you are selecting into
When I do those three things, I get something like this
create or replace trigger PASSENGER_BOOKING_T1
AFTER insert on PASSENGER_BOOKING
for each row
declare
l_seat flight.seat%type;
l_flight_id flight.flight_id%type;
begin
IF (:NEW.CLASS_TYPE = 'ECO')
THEN
SELECT F.AVL_SEATS_ECOCLASS,F.FLIGHT_ID
INTO l_seat, l_flight_id
FROM BOOKING B,
JOURNEY_FLIGHT J,
FLIGHT F
WHERE B.JOURNEY_ID = J.JOURNEY_ID
and F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (l_seat-1)
WHERE FLIGHT_ID = l_flight_id;
END IF;
end;​
Beyond those syntax errors, I would be shocked if the SELECT INTO statement was correct. A SELECT INTO must return exactly 1 row. Your query should almost certainly return multiple rows since there are no predicates that would restrict the query to a particular flight or a particular booking. Presumably, you want to join to one or more columns in the PASSENGER_BOOKING table.
Additionally, if this is something other than a homework assignment, make sure you understand that this sort of trigger does not work correctly in a multi-user environment.
just a wild guess
edit as Justin pointed out (thanks Justin) equality check
create or replace trigger "PASSENGER_BOOKING_T1"
AFTER
insert on "PASSENGER_BOOKING"
for each row
declare
v_flight_id FLIGHT.FLIGHT_ID%TYPE;
begin
IF (:NEW.CLASS_TYPE = 'ECO') THEN
SELECT F.ID into v_flight_id
FROM BOOKING B, JOURNEY_FLIGHT J, FLIGHT F
WHERE B.ID = :NEW.BOOKING_ID -- note that I've made this up
AND B.JOURNEY_ID = J.JOURNEY_ID AND F.FLIGHT_ID = J.FLIGHT_ID;
UPDATE FLIGHT
SET AVL_SEATS_ECOCLASS = (SEAT-1)
WHERE ID = v_flight_id;
END IF;
end;​

Resources