Presentation is loading. Please wait.

Presentation is loading. Please wait.

SOME COOL NMMI SQL TRIGGERS by Bryan Yates, New Mexico Military Institute in Roswell, NM

Similar presentations

Presentation on theme: "SOME COOL NMMI SQL TRIGGERS by Bryan Yates, New Mexico Military Institute in Roswell, NM"— Presentation transcript:

1 SOME COOL NMMI SQL TRIGGERS by Bryan Yates, New Mexico Military Institute in Roswell, NM My Info

2 In the beginning We migrated to ABT PowerCAMPUS in 2002 We realized ABT did a lot of things in triggers and we could also leverage this for a lot of business processes We decided that upgrades were too risky to create our own tables in Campus6, so we created a new Database called Institute. We initially didn’t know we could have multiple insert/update/delete triggers per table, so we initially called a stored procedure called from ABT’s trigger and re-inserted it after every upgrade We check to ensure we’re in the live database before pushing data to Institute, this could be improved if all tables were in the Campus6 database. Testing with db copies would be better.

3 Our first audit trigger -- Use the Specify Values for Template Parameters -- command (Ctrl-Shift-M) to fill in the parameter -- values below. -- use ALTER TABLE ADD create_date datetime NULL, create_time datetime NULL, create_user varchar(12) NULL, revision_date datetime NULL, revision_time datetime NULL, revision_user varchar(12) NULL go CREATE TRIGGER ti_audit_ ON FOR INSERT AS /* Audit Fields */ declare @I_Id varchar(20) select @I_Id = from Inserted exec sp_Audit_Create ' ',' ',@I_Id go CREATE TRIGGER tu_audit_ ON dbo. FOR UPDATE AS /* Audit fields */ declare @I_Id varchar(20) select @I_Id = from Inserted exec sp_Audit_Revision ' ',' ',@I_Id go

4 Lessons learned Only works on first item if bulk insert done Insert into tbl (id,name) values (1,’a’),(2,’b’) Inset into tbl (id,name) select top 2 id,name from tbl2 Templates are cool, sometimes Only usable on tables with a single primary key Should have used NMMI in the name of the trigger, and a description, like ti_TBL_NMMI_audit Eventually learned that you can make triggers for insert AND update in the same trigger

5 New database table, who did that? -- ============================================= -- Author: Gary Hill -- Create date: 6/6/2013 -- Description: Send an e-mail to programmers when a new database is created. -- ============================================= CREATE TRIGGER [trg_DDL_CreateDatabase] ON ALL SERVER FOR CREATE_DATABASE AS declare @results varchar(4000), @subjectText varchar(200) SET @subjectText = 'DATABASE Created on ' + @@SERVERNAME + ' by ' + SUSER_SNAME() SET @results = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)')) EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DBmailprofile', @recipients = '', @body = @results, @subject = @subjectText GO

6 New database table, the email

7 Database Mail

8 View existing Email profiles exec msdb.dbo.sysmail_help_account_sp columnsrows account_id23 nameProgrammersSQL Server Mailer descriptionISCT Programmers display_nameProgrammersDBMailAccount servertypeSMTP port25 usernameNULL use_default_credentials00 enable_ssl00

9 tu_residency_nmmi, room changes Simple enough, let’s track some room changes, but not just between semesters Originally used to help keep the phone number with the student Extended to keep the switch and port info stored in FAX field to know if student port was locked (loss of privilege). Abandoned by IT due to in room phones going away and edge smart switch management improvements Housing office still uses to review problem cases

10 tu_residency_nmmi if (isnull(@D_DORM_ROOM,'')<>isnull(@I_DORM_ROOM,'')) -- only the guts are shown AND (@I_ACADEMIC_SESSION='') AND (DB_NAME() = 'CAMPUS6') exec Institute.dbo.sp_room_change @I_PEOPLE_ID, @D_DORM_ROOM, @I_DORM_ROOM, @I_MAIL_SLOT, @I_ACADEMIC_YEAR, @I_ACADEMIC_TERM, @I_REVISION_DATE, @I_REVISION_TIME, @I_REVISION_OPID, @I_REVISION_TERMINAL -- BAY 7/22/09 to allow room/troop/status updates to go straight into Housing if @I_ACADEMIC_SESSION='' AND DB_NAME() = 'CAMPUS6' AND (isnull(@D_DORM_ROOM,'') <> isnull(@I_DORM_ROOM,'') or isnull(@D_DORM_Plan,'') <> isnull(@I_DORM_Plan,'') or isnull(@D_Food_Plan,'') <> isnull(@I_Food_Plan,'') ) AND @I_PEOPLE_CODE_ID IN (select PEOPLE_CODE_ID from institute.dbo.CMDT_Housing_INFO) update institute.dbo.CMDT_Housing_INFO set Room_Id = @I_Dorm_Room,Troop = @I_Dorm_Plan,Status = @I_Food_Plan where people_code_id = @I_PEOPLE_CODE_ID

11 sp_room_change INSERT INTO Institute.dbo.Room_Changes (People_ID, Old_Room_ID, Old_Phone_Number, New_Room_ID, New_Phone_Number, Academic_Year, Academic_Term, Create_Date, Create_Time, Create_User, Create_Terminal, Revision_Date, Revision_Time, Revision_User, Revision_Terminal) VALUES (@people_id, @old_room_id, 'n/a', -- @old_phone_number @new_room_id, 'n/a',@academic_year, @academic_term, @create_date, @create_time, @create_opid, @create_terminal, @create_date, @create_time, @create_opid, @create_terminal) -- update campus address with new phone number and mail slot update CAMPUS6.dbo.AddressSchedule Set Address_Line_1 = 'NMMI Mail Slot '+@mail_slot from CAMPUS6.dbo.AddressSchedule where People_org_code_id='P'+@people_id and Address_type = 'CAMP' and Status = 'A' update campus6.dbo.RESIDENCY set DORM_ROOM = @new_room_id from campus6.dbo.RESIDENCY RES join semesterinfo SI on SI.academic_year = res.ACADEMIC_YEAR and si.academic_term = res.ACADEMIC_TERM and si.academic_session = res.ACADEMIC_SESSION and si.offset > 0 where res.PEOPLE_CODE_ID = 'P' + @people_id

12 StudentFinancial This Campus6 table gets created on the roll and on certain events during in-processing We use the PaymentPlan field to define the “Financial Advisor” for each student. This is usually based on the first letter of their last name, but full or partial AGA scholarship recipients, and some other exceptions exist Business Office didn’t have rights to StudentFinancial table because Registrar wanted full control over Tuition_Plan and Tuition_Exemption.

13 StudentFinancial trigger CREATE trigger [dbo].[ti_studentfinancialNMMIfinAdv] on [dbo].[STUDENTFINANCIAL] for INSERT as /*********************************************************************** Description: Update non-AGA Financial Advisors using the PaymentPlan field Parameters: History: 1/30/2012 BAY created to help auto-maintain Financial Advisors ************************************************************************/ update studentfinancial set PAYMENT_PLAN = FA.PaymentPlanCode from studentfinancial SF join inserted INS on INS.people_code_id = SF.people_code_id and INS.academic_year = SF.academic_year and INS.academic_term = SF.academic_term and INS.academic_session = SF.academic_session join PEOPLE PEO on PEO.PEOPLE_CODE_ID = SF.PEOPLE_CODE_ID join Institute.dbo.BO_STMT_Financial_Advisor FA on charindex(LEFT(PEO.LAST_NAME,1),FA.FIRST_LETTER) > 0 where SF.ACADEMIC_SESSION = '01' and isnull(SF.TUITION_EXEMPTION,'') not in ('aga','aganon') and isnull(SF.PAYMENT_PLAN,'') = '' GO

14 StudentFinancial, Supporting data select * from Institute.dbo.BO_STMT_Financial_Advisor -- drives triggers, and pre/billing groupings select * from campus6.dbo.CODE_PAYMENTPLAN -- shows in PowerCAMPUS PaymentPlanCodeFIRST_LETTERAdvisorNameAdvisorPhoneusername 1FAABCMrs. Angelia Horton(575) 624-8083angelia 2FAHIJKLMs. Shelly Wheeler(575) 624-8082shelly 3FADEFGMs. Rebecca Quintero(575) 624-8406quinter 4FAMNOMrs. Sarah Villarreal(575) 624-8084sarah 5FAPQRSMrs. Linda Stansell(575) 624-8077stansell 6FATUVWXYZCPT Ma Eva Heacox(575) 624-8089ma_eva AGANULLCPT Amanda Garcia(575) 624-8086garciaa CODE_VALUE_KEYCODE_VALUESHORT_DESCMEDIUM_DESCLONG_DESCSTATUS 1FA Mrs. Angelia HortonMrs. Angelia Horton at (575) 624-8083A 2FA Ms. Shelly WheelerMs. Shelly Wheeler at (575) 624-8082A 3FA Ms. Rebecca QuinteroMs. Rebecca Quintero at (575) 624-8406A 4FA Mrs Sarah VillarrealMrs. Sarah Villarreal at (575) 624-8084A 5FA Mrs. Linda StansellMrs. Linda Stansell at (575) 624-8077A 6FA CPT Ma Eva HeacoxCPT Ma Eva Heacox at (575) 624-8089A AGA CPT Amanda GarciaCPT Amanda Garcia at (575) 624-8086A

15 StudentFinancial summary I think this trigger is so cool, because of 2 things The trigger joins directly to the Inserted table, meaning any bulk imports are handled without “looping” over them The first initial of the last name join is really slick

16 Absent 2 or more times in one day? CREATE TRIGGER [dbo].[ti_tranattendance_nmmi] ON [dbo].[TRANATTENDANCE] FOR INSERT AS DECLARE @I_PEOPLE_CODE nvarchar(1) DECLARE @I_PEOPLE_ID nvarchar(9) DECLARE @I_PEOPLE_CODE_ID nvarchar(10) DECLARE @I_ACADEMIC_YEAR nvarchar(4) DECLARE @I_ACADEMIC_TERM nvarchar(10) DECLARE @I_ACADEMIC_SESSION nvarchar(10) DECLARE @I_EVENT_ID nvarchar(15) DECLARE @I_EVENT_SUB_TYPE nvarchar(4) DECLARE @I_SECTION nvarchar(4) DECLARE @I_ATTENDANCE_DATE datetime DECLARE @I_ATTENDANCE_STATUS nvarchar(10) DECLARE @I_CREATE_DATE datetime DECLARE @I_CREATE_TIME datetime DECLARE @I_CREATE_OPID nvarchar(8) DECLARE @I_CREATE_TERMINAL nvarchar(4) DECLARE @I_REVISION_DATE datetime DECLARE @I_REVISION_TIME datetime DECLARE @I_REVISION_OPID nvarchar(8) DECLARE @I_REVISION_TERMINAL nvarchar(4) DECLARE @I_ABT_JOIN nvarchar(1) DECLARE @I_COMMENTS nvarchar(max) DECLARE @ROWS INT DECLARE @TranAttendanceId int SELECT @ROWS = @@ROWCOUNT -- this will loop over multiple line inserts correctly If @Rows <= 0 Return Set @TranAttendanceId = 0 Select @TranAttendanceId = (Select Min([TranAttendanceId]) From inserted Where [TranAttendanceId] > @TranAttendanceId) While @TranAttendanceId Is Not Null BEGIN Select @I_PEOPLE_CODE= PEOPLE_CODE, @I_PEOPLE_ID= PEOPLE_ID, @I_PEOPLE_CODE_ID= PEOPLE_CODE_ID, @I_ACADEMIC_YEAR= ACADEMIC_YEAR, @I_ACADEMIC_TERM= ACADEMIC_TERM, @I_ACADEMIC_SESSION= ACADEMIC_SESSION, @I_EVENT_ID= EVENT_ID, @I_EVENT_SUB_TYPE= EVENT_SUB_TYPE, @I_SECTION= SECTION, @I_ATTENDANCE_DATE= ATTENDANCE_DATE, @I_ATTENDANCE_STATUS= ATTENDANCE_STATUS, @I_CREATE_DATE= CREATE_DATE, @I_CREATE_TIME= CREATE_TIME, @I_CREATE_OPID= CREATE_OPID, @I_CREATE_TERMINAL= CREATE_TERMINAL, @I_REVISION_DATE= REVISION_DATE, @I_REVISION_TIME= REVISION_TIME, @I_REVISION_OPID= REVISION_OPID, @I_REVISION_TERMINAL= REVISION_TERMINAL, @I_ABT_JOIN= ABT_JOIN, @I_COMMENTS= COMMENTS FROM inserted WHERE TranAttendanceId = @TranAttendanceId If (DB_NAME() = 'CAMPUS6' and (@I_ATTENDANCE_STATUS in ('ABSENT','TARDY'))) -- move into Select @TranAttendanceId lines someday? Begin EXEC institute.dbo.sp_absence @I_PEOPLE_CODE_ID,@I_ACADEMIC_YEAR,@I_ACADEMIC_TERM, @I_ACADEMIC_SESSION,@I_EVENT_ID,@I_EVENT_SUB_TYPE,@I_SECTION, @I_ATTENDANCE_DATE, @I_ATTENDANCE_STATUS, @TranAttendanceId,@I_COMMENTS -- Ok, what real people would more likely do goes here from next slide End Select @TranAttendanceId = (Select Min( [TranAttendanceId] ) From inserted Where [TranAttendanceId] > @TranAttendanceId) --Get Next Id END

17 institute.dbo.sp_absence Our sp_absence stored procedure actually checks multiple data sources (two off campus reports, and infirmary reports) to see if it can excuse the user, defer the decision (can’t make a decision before the end of class, if in the infirmary), or enter a “Stick” (our homegrown violation system). Deferred decisions are checked again hourly If not excused, they receive a Stick Then an insert trigger on our Stick table checks for the same student 2 and more times today, and sends email Depends a lot on Faculty prompt Attendance reporting

18 Absent trigger, generalized for non-NMMI -- replace the “EXEC institute.dbo.sp_absence …” line in ti_tranattendance_nmmi with something like below, I did test this code -- email variables declare @esubject varchar(255), @emailto varchar(255), @ebody varchar(4000) select -- define email variables only if sum for the day >1 @esubject = PEO.LAST_NAME + ', ' + PEO.first_name + ' ' + right(PEO.people_code_id,9) + ' ABSENT '+ cast(COUNT(*) as varchar) + ' times today', @ebody = ' CRR Link ', @emailto = ';;;;' + case when EMPA.Email_Address IS not null then replace(empA.Email_Address + '',' ','') + ';' else '' end from TRANATTENDANCE TA join TRANATTENDANCE TA2 on TA.TranAttendanceId = @TranAttendanceId and TA2.People_Code_ID = TA.People_Code_ID and TA2.ATTENDANCE_DATE = TA.ATTENDANCE_DATE -- = limits per date report, not limited in WHERE to allow testing with any date join people PEO on PEO.PEOPLE_CODE_ID = TA.People_Code_ID JOIN Academic ACA on ACA.PEOPLE_CODE_ID = TA.PEOPLE_CODE_ID and ACA.ACADEMIC_YEAR = TA.ACADEMIC_YEAR and ACA.ACADEMIC_TERM = TA.ACADEMIC_TERM and ACA.ACADEMIC_SESSION = TA.ACADEMIC_SESSION left join institute.dbo.Employees EMPA -- view of active employees on EMPA.PEOPLE_ID = RIGHT(ACA.ADVISOR,9) -- or on 'P'+EMPA.PEOPLE_ID = ACA.ADVISOR -- which is better? where TA2.ATTENDANCE_STATUS in ('ABSENT') and TA.ATTENDANCE_STATUS in ('ABSENT') -- add Tardy if you want and CONVERT (date, GETDATE())= TA.ATTENDANCE_DATE -- limit to today, comment out for testing group by PEO.People_Code_ID,PEO.LAST_NAME,PEO.first_name,EMPA.Email_Address having COUNT(*) > 1 if (@esubject is not null) -- if email variables are not null, then send something off begin EXEC msdb.dbo.sp_send_dbmail @profile_name = 'DBmailprofile',@body_format = 'HTML‘, @from_address = '',@subject = @esubject, @body = @ebody, @importance = 'High',@recipients = @emailto -- '' – switch around for testing end

19 Email result

20 Summary, Questions Please nit-pick my code, Should ANSI_NULLS ON and QUOTED_IDENTIFIER ON ? Ok, Better, Best practices Dependencies across databases “Base View” starting points for departments Download I’m staying on campus & love to talk geek Other valid geek topics include Raspberry Pi, and C# I am also finishing a campus migration from Exchange 2007 to Office 365, if you want to talk about that My Info

Download ppt "SOME COOL NMMI SQL TRIGGERS by Bryan Yates, New Mexico Military Institute in Roswell, NM"

Similar presentations

Ads by Google