Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
sfalter
Starting Member
15 Posts |
Posted - 2010-10-28 : 12:52:03
|
| The particulars:Running SQL 2008 (64-bit) (SQL Server 10.0.2531)on Windows Server 2003 R2 SP2 x64 EditionApplication: Web applications use a user table that includes an encryption setting based on the user's name. The name information is maintained by the mainframe Payroll system. When a name changes or a user is terminated, the Payroll system generates this information in a flat file. My web application database needs to import this data and, in the case of name change, update the encryption or in the case of a termination delete the access.To accomplish this I have a scehduled SQL job that runs every morning at 5:00 am. The job consists of 4 steps, Step 1 copies the flat file from a share on one server to the SQL server. Step 2 truncates a table I use to receive this flat file. Step 3 executes a SSIS package to import the flat file to a SQL table. Step 4 executes a SP that does the actual updating of the user tables.The problem:This job will run for several days, even up to a month at at time, with no problems. Occasionaly, however, I get notification that the job failed.As the SP is executing it writes to an audit table everything it does. When the job fails the history of the job indicates the following error:Executed as user: SCODMZ1\sqlservice. Invalid object name 'wasp_log'. [SQLSTATE 42S02] (Error 208). The step failed.When I check the data against the log I ALWAYS find that all the data was processed and the log is complete.The procedure errors like this maybe 2 or 3 times a month, sometimes less often and a few times more often. The problem is, I can't ignore the notification assuming there is no problem, naturally, there could be other issues sometime, so all the checking of the data has to occur. This can, at times, be quite time consuming.So, I'm hoping for someone to help point me in a direction I haven't already gone to find this quirk.Current Stats: The job was successful 10/22, 10/23, 10/24, 10/25.Failure notificaton on 10/26 and 10/27.Successful again this morning 10/28.Following is the SP. Note by the modification statements in the beginning that I have already tried fully qualifying the table name almost a year ago to no avail. Hope someone can help.Thanks in advance for everyone's time.--------------------------------------SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO/*---------------------------------------------------------------------------------------------------------------Changes:Date Programmer Reason---------------------------------------------------------------------------------------------------------------10-22-2007 Steve Falter Created to update adm_user from data received from WASP12-07-2009 Steve Falter Added DAF_Global.dbo. qualifier to all tables hoping to avoid job failure status10-01-2010 Steve Falter Modified all user encryption to use new function***************************************************************************************************************/ALTER procedure [dbo].[upd_wasp_info] asset nocount ontruncate table DAF_Global.dbo.wasp_procinsert into DAF_Global.dbo.wasp_proc select * from DAF_Global.dbo.waspdeclare @max_count int, @count int, @wasp_data varchar(100), @user_name varchar(75), @user_old varchar(75), @user_new varchar(75), @agency_code char(3), @first_name varchar(25), @last_name varchar(50), @taction char(1), @caction char(2), @ency_old varchar(50), @ency_new varchar(50), @user_id int, @log_id int, @error_flag int, @count2 intselect @max_count = ISNULL((select count(*) from DAF_Global.dbo.wasp_proc),0)set @count = 1while @max_count > 0 and @count <= @max_count begin set @wasp_data = (select w_data from DAF_Global.dbo.wasp_proc where w_id = @count) set @taction = substring(@wasp_data,1,1) set @caction = substring(@wasp_data,1,2) set @error_flag = 0 if @taction = 'T' begin goto Terminations end if @caction <> 'CO' begin goto Fetch_Next end set @user_old = substring(@wasp_data,15,75) set @user_name = upper(rtrim(@user_old)) set @agency_code = substring(@wasp_data,3,3) set @ency_old = actual code not included set @user_id = 0 set @user_id = (select user_id from DAF_Global.dbo.adm_user where user_name_enc = @ency_old) insert into DAF_Global.dbo.wasp_log values (getdate(), @agency_code, @user_id, @user_old, @ency_old, '', '','','','','NOT PROCESSED') set @log_id = (select max(log_id) from DAF_Global.dbo.wasp_log) if (@user_id = 0) or (@user_id is null) begin set @error_flag = 1 update DAF_Global.dbo.wasp_log set user_status = 'USER NOT FOUND', process_status = '' where log_id = @log_id goto Fetch_Next end set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from DAF_Global.dbo.wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CF' begin set @error_flag = 1 goto End_First_Name end set @first_name = substring(@wasp_data,15,50) update DAF_Global.dbo.wasp_log set new_first = @first_name where log_id = @log_id End_First_Name: set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from DAF_Global.dbo.wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CL' begin set @error_flag = 1 goto End_Last_Name end set @last_name = substring(@wasp_data,15,50) update DAF_Global.dbo.wasp_log set new_last = @last_name where log_id = @log_id End_Last_Name: set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from DAF_Global.dbo.wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CU' begin set @error_flag = 1 goto Fetch_Next end set @user_new = substring(@wasp_data,15,75) if (@user_new = 'null') or (@user_new = ' ') begin set @error_flag = 1 goto Fetch_Next end set @user_name = upper(rtrim(@user_new)) set @ency_new = actual code not included update DAF_Global.dbo.adm_user set first_name = @first_name, last_name = @last_name, user_name_enc = @ency_new where user_id = @user_id set @count2 = 0 select @count2 = (select count(*) from DAF_Global.dbo.adm_app where user_id = @user_id and app_id = 'PCARD') if @count2 > 0 begin exec pcard.dbo.upd_from_wasp @user_id, @first_name, @last_name end set @count2 = 0 select @count2 = (select count(*) from adm_app where user_id = @user_id and app_id = 'PMTSVCS') if @count2 > 0 begin exec pmtsvcs.dbo.upd_from_wasp @user_id, @first_name, @last_name end update DAF_Global.dbo.wasp_log set new_user = @user_new, new_ency = @ency_new, user_status = 'NAME CHANGED', process_status = 'adm_user UPDATED' where log_id = @log_id goto Fetch_Next Terminations: set @user_old = substring(@wasp_data,14,75) set @user_name = upper(rtrim(@user_old)) set @agency_code = substring(@wasp_data,2,3) set @ency_old = actual code not included set @user_id = 0 set @user_id = (select user_id from DAF_Global.dbo.adm_user where user_name_enc = @ency_old) insert into DAF_Global.dbo.wasp_log values (getdate(), @agency_code, @user_id, @user_old, @ency_old, '', '','','','','NOT PROCESSED') set @log_id = (select max(log_id) from DAF_Global.dbo.wasp_log) if (@user_id = 0) or (@user_id is null) begin set @error_flag = 1 update DAF_Global.dbo.wasp_log set user_status = 'USER NOT FOUND', process_status = '' where log_id = @log_id goto Fetch_Next end delete DAF_Global.dbo.adm_app where user_id = @user_id and agency_code = @agency_code update DAF_Global.dbo.wasp_log set user_status = 'TERMINATION', process_status = 'adm_app DELETED' where log_id = @log_id Fetch_Next: set @count = @count + 1 end |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-09 : 11:11:41
|
| It seems everyone here is as stumped as I am.I modified the stored procedure and it has not sent the failure message for 10 days or so. Not definitive yet, it had been successful that many consecutive days before, but still....I wanted to post my simple modification in case someone here could say "Oh yes, that would fix it!!!". Two places where I inserted a row then immediatley read for the auto increment column I put a 1 second delay. Code: insert into wasp_log values (getdate(), @agency_code, @user_id, @user_old, @ency_old, '', '','','','','NOT PROCESSED') waitfor delay '00:00:01' set @log_id = (select max(log_id) from wasp_log)Thoughts? |
 |
|
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2010-11-09 : 13:38:56
|
| 1. What step# does this sproc run on in the SSIS2. Can you show us the TSQL command that happen in the other steps3. 5am hmm, could there be another process that is killing DAF_Global server such as a backup or something else during that time?4. try this in command window against DAF_Global if it has it's own ip ping DAF_Global -t >> DAF_Global_ping_test.txt and let it run for a few minutes. Are there connectivity issues? bad nic or whatever.5. Run SQL profile dumping into a table parallel to the SSIS run time. That will give you lots of good info. If you don't have the passion to help people, you have no passion |
 |
|
|
AndrewMurphy
Master Smack Fu Yak Hacker
2916 Posts |
Posted - 2010-11-10 : 06:11:45
|
| What aren't you looking for to pickup the system identity variables?reading a table to get the max record is a waste of resources...especially when the system will tell you what the last record you inserted was. (I'm pressuming that log_id is an identity column) |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-10 : 10:11:47
|
| After 5 days of success the job issued the FAILED message again this morning.Let me reiterate, ALL the data is updated as its supposed to be, the log table specified in the error message as the Invalid object name is COMPLETELY UPDATED and correct. I spent 10-15 minutes verifying that there really wasn't an error, the job really didn't fail.To answer the questions posed:It is a SQL job issuing the failure, not the SSIS package. Here are the steps of the SQL job.1)Operating system command to copy the flat file from the payroll server to the SQL Server. copy \\payrollserver\flatfile.txt d:\flatfile.txtThis step has never failed.2)T-SQL to truncate the table that will have the rows inserted from the flat file via SSIS. T-SQL = truncate table waspThis step has never failed.3)SSIS from SSIS Package Store, stored in MSDB. This is a simple SSIS package that imports the flat file into the table previously truncated in Step 2.This step has never failed.4)T-SQL command to execute the stored procedure. T-SQL = exec upd_wasp_infoThis is the step issuing the false failure.The scheduled time of 5:00 am was chosen for various reasons. The SQL backups on the server begin at 9:00 pm every evening and are done by midnight. We have a Tivoli backup service that begins at midnight and is usually finished by 2:00 am. Even though all our applications are advertised to have 24/7 availability we know that for most of our agencies work doesn't begin in earnest until 7:00 am. There are some people who begin their day earlier so we scheduled this function for 5:00 am, hoping to escape the load on the server from the backups and still have name changes and terminations from the day before updated before the work day begins.The database DAF_Global is on the same server as the other application databases. I'm not sure if I can ping it or not, if you really believe it will tell me anything I'll attempt to do this.I will schedule a profile to run.I understand reading the table for the max id is not the best coding. I actually inherited the support of this application after the migration to SQL 2008 from SQL 2000. I had been asked about these reported job failures before the migration (Yes, it did this on SQL 2000 as well) but now I can actually explore the issues and make changes. It was this very functionality I had come to question when I put the delay in, hoping it was the read for max value immediately after the insert that was causing the error. I will modify this part and see if that helps. The problem is, it might run for a month before it gives me the error, whether I change anything or not.Thanks for the feedback, previous and upcoming. |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-10 : 10:40:30
|
| couple thoughts:- the error: "Invalid object name 'wasp_log'." may be a red herring. But is it possible that there is a maintenance plan running at the same time? Perhaps the table is actually unavailable for short periods of time because of an unrelated operation.- what is going on in these SPs: (pcard.dbo.upd_from_wasp, pmtsvcs.dbo.upd_from_wasp)? The error may be originating in them. Any explicit transactions or cursors?- I notice that other than updates to the log table there is no real process logging going on. It is good practice to set nocount off and add print statements (indicating what step is about to run plus a timestamp) before every statement in the process then redirect the output to a log file in the job step. That really helps to diagnose problems after the fact. We have a generic process that re-names the .log with a date suffix then adds it to a zip archive. That practice has proven to be extremely helpful to trouble shoot performance and error issues.- finally I see that your SP is extremely "procedural" in nature with loops and gotos. Very non-sql - very non-set-based. It may be time to re-write the whole process :) Be One with the OptimizerTG |
 |
|
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2010-11-10 : 11:17:45
|
| upcoming feedback :)The problem is, it might run for a month before it gives me the error, whether I change anything or not.you need to setup a dev/qa lab server right now where you can try this on right now and to your heart's delight.If you don't have the passion to help people, you have no passion |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-10 : 11:57:39
|
| Holy crap!! Problem solved!! TG, thanks for asking about the two sps getting called within the one I've been talking about. One of them, the pmtsvcs.dbo.upd_from_wasp is attempting to insert audit rows into a table named wasp_log and guess what....it doesn't exist. So, on the fairly rare occasions this gets called, the job throws the error. I wouldn't have found it if not for you asking and me going in to grab the code to explain them to you. Damn, ignorance is bliss and this morning I'm feeling quite blissful.I was planning on responding to your observation regarding the sp and its 'procedural' nature, so if you still have a few seconds keep reading. Lets start with my background. I began my IT career writing accounting software in COBOL on Burroughs mini-computers in 1980. We migrated our suite of applications to IBM's RS6000 using Micro Focus COBOL on IBM's AIX unix operating system. When I came to work for the State of Idaho in 1999 I was still writing COBOL on IBM Mainframe (am I allowed to use the word Mainframe here?). So, naturally, I'm very comfortable with this type of 'procedural' SQL code.However, old school as I am, I still recognize and feel the need to do things the right way and am very intent on modifying all the SQL code I come across to set-based, efficient code. I just don't always see the light, sometimes I don't even know where to look for the light switch.Now, I read these, and other, forums regularly and hardly ever leave without learning something. And yes, I often 'borrow' sample code. But, I'm not the kind of person that will come here and post a scenario in hopes that someone else will come along and give the code needed to do my task. Or do my job.So I'll ask you, and anyone else still reading, if you are interested in showing me how the task I've described can be done more effectively and in a set-based manner I'd be more than happy to supply you with sample data and explain the procedure.One more thing....yosiasz, I do have a SIM and DEV server at my disposal. So, experimenting with set-based code won't be an issue.Again, thanks.... |
 |
|
|
yosiasz
Master Smack Fu Yak Hacker
1635 Posts |
Posted - 2010-11-10 : 12:13:28
|
basically your database manipulation does the following1. on set @ency_old = actual code not includedis it doing something with something like this? substring(@wasp_data,3,3)2. is there a relationship between DAF_Global.dbo.adm_user and DAF_Global.dbo.wasp_log, I assume it is @ency_old3. Can you provide a table schema for wasp_log?/* */insert into DAF_Global.dbo.wasp_log values (getdate(),@agency_code, @user_id, @user_old, @ency_old, '','','','','','NOT PROCESSED')update DAF_Global.dbo.wasp_log set user_status = 'USER NOT FOUND',process_status = ''where log_id = @log_id/* */delete DAF_Global.dbo.adm_app where user_id = @user_id and agency_code = @agency_codeupdate DAF_Global.dbo.wasp_log set user_status = 'TERMINATION',process_status = 'adm_app DELETED'where log_id = @log_id/* */update DAF_Global.dbo.wasp_log set new_first = @first_name where log_id = @log_idupdate DAF_Global.dbo.adm_user set first_name = @first_name,last_name = @last_name,user_name_enc = @ency_newwhere user_id = @user_idupdate DAF_Global.dbo.wasp_log set new_user = @user_new,new_ency = @ency_new,user_status = 'NAME CHANGED',process_status = 'adm_user UPDATED'where log_id = @log_id am I correct, those are the 7 insert/update/deletes I seeIf you don't have the passion to help people, you have no passion |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-10 : 14:32:07
|
quote: Holy crap!! Problem solved!!
Awesome! Congrats...quote: ...how the task I've described can be done more effectively and in a set-based manner I'd be more than happy to supply you with sample data and explain the procedure.
I'm sure folks would be happy to try and help anyone who genuinely wants to change their process (thought and programming) from procedural to set-based.Go ahead and provide the DDL (create table scripts) for your tables and post some DML (insert statements) to provide a little sample data. Then post what the resulting data should be. Be sure to include descriptive business rules that we need to know to transform from before to after. Here is a link that may help with DDL/DML:http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspxBe One with the OptimizerTG |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-12 : 12:53:29
|
| Okay, I'll take you all up on the offer for assistance.First, it took me some time to get back here, yesterday (Nov 11) was a holiday for us. With that said:Let me shout out to all Veterans reading this forum. Thank you for all you've done and all you continue to do for our great country and for our freedom we enjoy and too often take for granted.My customers reach my applications via our home page which is all developed in Lotus Domino. Access is granted or not using a standard Lotus address book. I have a Domino agent in the Lotus database that takes the login name (user name) and encrypts it before passing it on to my application, developed in .NET. My application then finds this encryption in our DAF_Global database, adm_user table. If found, we then know the user id and processing continues. If not found the user is not authorized to use our applications.There are 40,000+- entries in the address book. Of those, 11,000 are valid users of my applications. The address book is maintained by the Payroll system, which I have nothing to do with and no control over. When a name change is processed in payroll the address book is updated. This does, of course, change this users encyrption so if I don't get this encryption changed on my side of life the person is unable to access my applications.Sort of the same thing happens when someone is terminated. The address book is updated to reflect the termination but because access to pay stubs and W2 information needs to stay in place for at least a year the person isn't deleted from the address book immediatley upon the termination. However, their access to my applications needs to be.To accomplish these two tasks the Payroll system generates this information nightly in the form of a flat text file and that's when my process takes over. Again, I have no control over the layout of this text file and given the current budget limitations asking for any kind of modification is not a possibility.For terminations the text file is the letter T followed by the 3 character agency code, the 9 character SSN and then the login (user) name of the employee.For name changes a little different format, the old user name is sent with the letters CO, agency, SSN and the old user name. Another line is then sent with the new first name (usually this isn't what changed unless there was an error in the initial set up of the individual). This line begins with the letters CF, agency, SSN and new first name. Then the new last name is sent, CL, agency, SSN and new last name. Last, the new user name is sent, CU, agency, SSN and new user name.My applications (there are a group of them with common entry page) are driven by the adm_user table holding the encrypted login and user id info and other data plus a adm_app table which indicates for a given user id what applications and for what agencies they can have access.My process for terminations:Get the old user name from the text file and create the encyrpted version. Look for this encrypted version in the adm_user table. If not found of course ignore the entry and go on. If I find it, I don't delete the entry in the adm_user table but I delete the access codes in adm_app. That way the name can still appear on audit reports from the different applications.My process for name changes:Again, get the old user name and create the encrypted version, look for it in adm_user. If not found ignore it and go on. If found I need to get the next line from the text file to get the new first name, get the next line to get the new last name, get the next line to get the new user name, encrypt it and update the adm_user table using the user id found from the search with the old user name. (Man, I hope this makes sense!!)Here is the test data. I've take some liberties with names and sent XXX for SSN but it is a fairly representive sample.T514XXXXXXXXXJASON JONES-514T513XXXXXXXXXLYNELL JONES-513CO340XXXXXXXXXJENNIFER JONES-340CF340XXXXXXXXXJENNIFER CL340XXXXXXXXXSMITHCU340XXXXXXXXXJENNIFER SMITH-340T514XXXXXXXXXBEVERLY JONES-514CO290XXXXXXXXXCOIT JONES-290CF290XXXXXXXXXCOIT CL290XXXXXXXXXSMITHCU290XXXXXXXXXCOIT SMITH-290T512XXXXXXXXXLORI JONES-512T513XXXXXXXXXBARBARA JONES-513CO290XXXXXXXXXBRYAN JONES-290CF290XXXXXXXXXBRYAN CL290XXXXXXXXXJONESCU290XXXXXXXXXnullT514XXXXXXXXXJENNIFER SMITH-514Here are the tables and the inserts to create some test data:CREATE TABLE [dbo].[adm_user]( [user_id] [int] IDENTITY(1,1) NOT NULL, [first_name] [varchar](50) NULL, [middle_name] [varchar](50) NULL, [last_name] [varchar](50) NULL, [user_name_enc] [varchar](32) NULL, [user_agency] [char](3) NULL, [email] [varchar](50) NULL, CONSTRAINT [PK_adm_user] PRIMARY KEY CLUSTERED ( [user_id] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]) ON [PRIMARY]insert into adm_user VALUES('JASON','','JONES','514JJONESENCY','514','JJONES514@EMAIL.COM')insert into adm_user VALUES('JENNIFER','','JONES','340JJONESENCY','340','JJONES340@EMAIL.COM')insert into adm_user VALUES('LORI','','JONES','512LJONESENCY','512','LJONES512@EMAIL.COM')CREATE TABLE [dbo].[adm_app]( [app_id] [varchar](50) NOT NULL, [user_id] [int] NOT NULL, [agency_code] [char](3) NOT NULL) ON [PRIMARY]insert into adm_app values ('PCARD',1,'514')insert into adm_app values('ADJUST',1,'514')insert into adm_app values('PCARD',2,'340')insert into adm_app values('PMTSVCS',3,'512')CREATE TABLE [dbo].[wasp_proc]( [w_id] [int] IDENTITY(1,1) NOT NULL, [w_data] [varchar](100) NULL) ON [PRIMARY]insert into wasp_proc values('T514XXXXXXXXXJASON JONES-514')insert into wasp_proc values('T513XXXXXXXXXLYNELL JONES-513')insert into wasp_proc values ('CO340XXXXXXXXXJENNIFER JONES-340')insert into wasp_proc values('CF340XXXXXXXXXJENNIFER')insert into wasp_proc values('CL340XXXXXXXXXSMITH')insert into wasp_proc values('CU340XXXXXXXXXJENNIFER SMITH-340')insert into wasp_proc values('T514XXXXXXXXXBEVERLY JONES-514')insert into wasp_proc values('CO290XXXXXXXXXCOIT JONES-290')insert into wasp_proc values('CF290XXXXXXXXXCOIT') insert into wasp_proc values('CL290XXXXXXXXXSMITH')insert into wasp_proc values('CU290XXXXXXXXXCOIT SMITH-290')insert into wasp_proc values('T512XXXXXXXXXLORI JONES-512')insert into wasp_proc values('T513XXXXXXXXXBARBARA JONES-513')insert into wasp_proc values ('CO290XXXXXXXXXBRYAN JONES-290')insert into wasp_proc values('CF290XXXXXXXXXBRYAN') insert into wasp_proc values('CL290XXXXXXXXXJONES')insert into wasp_proc values('CU290XXXXXXXXXnull')insert into wasp_proc values('T514XXXXXXXXXJENNIFER SMITH-514')CREATE TABLE [dbo].[wasp_log]( [log_id] [int] IDENTITY(1,1) NOT NULL, [log_date] [smalldatetime] NULL, [agency_code] [char](3) NULL, [user_id] [int] NULL, [old_user] [varchar](75) NULL, [old_ency] [varchar](50) NULL, [new_first] [varchar](50) NULL, [new_last] [varchar](50) NULL, [new_user] [varchar](75) NULL, [new_ency] [varchar](50) NULL, [user_status] [varchar](25) NULL, [process_status] [varchar](25) NULL) ON [PRIMARY]Here is what adm_user looks like before I run my process:id First Last Encyrption Agency1 JASON JONES JASON JONES-514ENCY 5142 JENNIFER JONES JENNIFER JONES-340ENCY 3403 LORI JONES LORI JONES-512ENCY 512Here is the adm_app table before my process:app_id user_id AgencyPCARD 1 514ADJUST 1 514PCARD 2 340PMTSVCS 3 512Here is the stored procedure: (Note, I've modified this from the initial version I posted most notably I changed the enctyption routine and commented out the calls to the two sps in other databases)ALTER procedure [dbo].[upd_wasp_info] asset nocount ondeclare @max_count int, @count int, @wasp_data varchar(100), @user_name varchar(75), @user_old varchar(75), @user_new varchar(75), @agency_code char(3), @first_name varchar(25), @last_name varchar(50), @taction char(1), @caction char(2), @ency_old varchar(50), @ency_new varchar(50), @user_id int, @log_id int, @error_flag int, @count2 intselect @max_count = ISNULL((select count(*) from wasp_proc),0)set @count = 1while @max_count > 0 and @count <= @max_count begin set @wasp_data = (select w_data from wasp_proc where w_id = @count) set @taction = substring(@wasp_data,1,1) set @caction = substring(@wasp_data,1,2) set @error_flag = 0 if @taction = 'T' begin goto Terminations end if @caction <> 'CO' begin goto Fetch_Next end set @user_old = substring(@wasp_data,15,75) set @user_name = upper(rtrim(@user_old)) set @agency_code = substring(@wasp_data,3,3) set @ency_old = @user_old+'ENCY' set @user_id = 0 set @user_id = (select user_id from adm_user where user_name_enc = @ency_old) insert into wasp_log values (getdate(), @agency_code, @user_id, @user_old, @ency_old, '', '','','','','NOT PROCESSED') set @log_id = SCOPE_IDENTITY() if (@user_id = 0) or (@user_id is null) begin set @error_flag = 1 update wasp_log set user_status = 'USER NOT FOUND', process_status = '' where log_id = @log_id goto Fetch_Next end set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CF' begin set @error_flag = 1 goto End_First_Name end set @first_name = substring(@wasp_data,15,50) update wasp_log set new_first = @first_name where log_id = @log_id End_First_Name: set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CL' begin set @error_flag = 1 goto End_Last_Name end set @last_name = substring(@wasp_data,15,50) update wasp_log set new_last = @last_name where log_id = @log_id End_Last_Name: set @count = @count + 1 if @count > @max_count begin set @error_flag = 1 goto Fetch_Next end set @wasp_data = (select w_data from wasp_proc where w_id = @count) set @caction = substring(@wasp_data,1,2) if @caction <> 'CU' begin set @error_flag = 1 goto Fetch_Next end set @user_new = substring(@wasp_data,15,75) if (@user_new = 'null') or (@user_new = ' ') begin set @error_flag = 1 goto Fetch_Next end set @user_name = upper(rtrim(@user_new)) set @ency_new = @user_name+'ENCY' update adm_user set first_name = @first_name, last_name = @last_name, user_name_enc = @ency_new where user_id = @user_id set @count2 = 0 select @count2 = (select count(*) from adm_app where user_id = @user_id and app_id = 'PCARD') --if @count2 > 0 --begin --exec pcard.dbo.upd_from_wasp @user_id, @first_name, @last_name --end set @count2 = 0 select @count2 = (select count(*) from adm_app where user_id = @user_id and app_id = 'PMTSVCS') --if @count2 > 0 --begin --exec pmtsvcs.dbo.upd_from_wasp @user_id, @first_name, @last_name --end update wasp_log set new_user = @user_new, new_ency = @ency_new, user_status = 'NAME CHANGED', process_status = 'adm_user UPDATED' where log_id = @log_id goto Fetch_Next Terminations: set @user_old = substring(@wasp_data,14,75) set @user_name = upper(rtrim(@user_old)) set @agency_code = substring(@wasp_data,2,3) set @ency_old = @user_old+'ENCY' set @user_id = 0 set @user_id = (select user_id from adm_user where user_name_enc = @ency_old) insert into wasp_log values (getdate(), @agency_code, @user_id, @user_old, @ency_old, '', '','','','','NOT PROCESSED') set @log_id = SCOPE_IDENTITY() if (@user_id = 0) or (@user_id is null) begin set @error_flag = 1 update wasp_log set user_status = 'USER NOT FOUND', process_status = '' where log_id = @log_id goto Fetch_Next end delete adm_app where user_id = @user_id and agency_code = @agency_code update wasp_log set user_status = 'TERMINATION', process_status = 'adm_app DELETED' where log_id = @log_id Fetch_Next: set @count = @count + 1 endThe end results:adm_userid First Last Encyrption Agency1 JASON JONES JASON JONES-514ENCY 5142 JENNIFER SMITH JENNIFER SMITH-340ENCY 3403 LORI JONES LORI JONES-512ENCY 512adm_appapp_id user_id AgencyPCARD 2 340the log table wasp_log:1 2010-11-12 09:51:00 514 1 JASON JONES-514 JASON JONES-514ENCY TERMINATION adm_app DELETED2 2010-11-12 09:51:00 513 NULL LYNELL JONES-513 LYNELL JONES-513ENCY USER NOT FOUND 3 2010-11-12 09:51:00 340 2 JENNIFER JONES-340 JENNIFER JONES-340ENCY JENNIFER SMITH JENNIFER SMITH-340 JENNIFER SMITH-340ENCY NAME CHANGED adm_user UPDATED4 2010-11-12 09:51:00 514 NULL BEVERLY JONES-514 BEVERLY JONES-514ENCY USER NOT FOUND 5 2010-11-12 09:51:00 290 NULL COIT JONES-290 COIT JONES-290ENCY USER NOT FOUND 6 2010-11-12 09:51:00 512 3 LORI JONES-512 LORI JONES-512ENCY TERMINATION adm_app DELETED7 2010-11-12 09:51:00 513 NULL BARBARA JONES-513 BARBARA JONES-513ENCY USER NOT FOUND 8 2010-11-12 09:51:00 290 NULL BRYAN JONES-290 BRYAN JONES-290ENCY USER NOT FOUND 9 2010-11-12 09:51:00 514 NULL JENNIFER SMITH-514 JENNIFER SMITH-514ENCY USER NOT FOUNDSo, that's it. As always, I thank you for your time and help and I'm really looking forward to what you come up with. |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-12 : 15:21:08
|
| When I run your code as is the entire log is "user not found". Looks like the result of this (set @ency_old = @user_old+'ENCY') never matches with adm_user.user_name_enc. So I can't really see the code do anything.But it seems like what you've specified in your last post is very do-able but I would need to confirm:- The [user_name_enc] correlates to: <the three character preceding the SSN> + <FirstInitial> + <LastName> + 'ENCY'- for Terminations the SSN starts at the 5th character- for all other rows the SSN starts at the 6th characterThe big question as to whether this can be converted to set-based is what happens in the called SPs which you've excluded from this sample code. But the updates to adm_user and the inserts to wasp_log based - on my assumptions above- should be pretty easy. I'll work on that after I post this...EDIT:what happens when Jennifer and Jason Jones both have the same user_agency? Won't their [user_name_enc] be duplicated?514JJONESENCY340JJONESENCYBe One with the OptimizerTG |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-12 : 18:07:02
|
Ok - I'm sure this has holes in it as far as everything you need but perhaps it will spark your imagination for thinking set-based. This basic logic could have been done with individual temp tables or nested derived tables (sub queries in FROM clause) or even one big expression statement - but I chose to use a series of common table expressions (CTEs). I'll take a look again later - I won't be surprised if there is a much simpler solution than this but here is first cut:From the resulting #wasp_proc table you could insert to your wasp_log as well as update adm_user.EDIT:forgot to mention that I made your SSNs unique for my purposes:insert into wasp_proc values('T514XXXXXXX01JASON JONES-514')insert into wasp_proc values('T513XXXXXXX02LYNELL JONES-513')insert into wasp_proc values('CO340XXXXXXX03JENNIFER JONES-340')insert into wasp_proc values('CF340XXXXXXX03JENNIFER')insert into wasp_proc values('CL340XXXXXXX03SMITH')insert into wasp_proc values('CU340XXXXXXX03JENNIFER SMITH-340')insert into wasp_proc values('T514XXXXXXX04BEVERLY JONES-514')insert into wasp_proc values('CO290XXXXXXX05COIT JONES-290')insert into wasp_proc values('CF290XXXXXXX05COIT')insert into wasp_proc values('CL290XXXXXXX05SMITH')insert into wasp_proc values('CU290XXXXXXX05COIT SMITH-290')insert into wasp_proc values('T512XXXXXXX06LORI JONES-512')insert into wasp_proc values('T513XXXXXXX07BARBARA JONES-513')insert into wasp_proc values('CO290XXXXXXX08BRYAN JONES-290')insert into wasp_proc values('CF290XXXXXXX08BRYAN')insert into wasp_proc values('CL290XXXXXXX08JONES')insert into wasp_proc values('CU290XXXXXXX08null')insert into wasp_proc values('T514XXXXXXX09JENNIFER SMITH-514')create table #wasp_proc (ssn char(9) ,enc char(3) ,isTerminated bit ,firstname varchar(75) ,lastname varchar(75) ,user_name_enc varchar(75) ,[user] varchar(75));with offset (w_id, offset, w_data) as( select w_id ,case when left(w_data,1) = 'T' then 0 else 1 end ,w_data from wasp_proc ),parse (w_id, [action],[enc],[ssn],[value]) as( select w_id ,substring(w_data, 1, 1+offset) ,substring(w_data, 2+offset, 3) ,substring(w_data, 5+offset, 9) ,substring(w_data, 14+offset, 75) from offset ),final (ssn,enc,isTerminated,firstname,lastname,[user]) as( select ssn ,max(enc) enc ,max(case when action = 'T' then 1 else 0 end) isTerminated ,max(case when action = 'CF' then [value] when action = 'T' then substring([value],1, isNull(nullif(charindex(' ', [value]),0),75)-1) end) FirstName ,max(case when action = 'CL' then [value] when action = 'T' then replace(substring([value],isNull(nullif(charindex(' ', [value]),0)+1,1), 75),'-'+enc,'') end) LastName ,max(case when action in ('T','CO') then [value] end) as [user] from parse group by ssn)insert #wasp_proc (ssn ,enc ,isTerminated ,firstname ,lastname ,user_name_enc ,[user])select ssn ,enc ,isTerminated ,firstname ,lastname ,enc + left(firstname,1) + lastname + 'ENCY' as user_name_enc ,[user]from finalselect t.* ,au.*from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encBe One with the OptimizerTG |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-15 : 09:45:04
|
| TG,I will start going through your example today, I really appreciate the effort. But first I wanted to quickly answer your questions so you'd have more information.The two sps called are in applications that were in place prior to our centralizing the security in the DAF_Global database. They each have their own user table with user id(s) and name information. The procedure we are dealing with here sends these two application sps the user_id, first_name and last_name, they then update the user tables in their own database:ALTER procedure [dbo].[upd_from_wasp]@user_id int,@user_first varchar(25),@user_last varchar(50)asset nocount ondeclare @new_user char(75)set @new_user = rtrim(@user_last) + ' ' + rtrim(@user_first)update pcard_user set first_name = @user_first, last_name = @user_last, user_name = @new_userwhere user_id = @user_idYour assumption regarding the encryption would be correct had I not neglected to mention that I simplified the encryption methodology in my example. In reality, the user name is sent to a function that first adds some characters, runs the result through an encryption using fn_varbintohexstr and t-sql hashbytes. This result is then sent through the function again using a different option of hashbytes. The end result is a 32 character hex code. I also have not looked again at the test data I sent so I don't know why you weren't getting any results. I'll try to get back to that today as well.Thanks again. |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-15 : 11:03:18
|
| Sounds like it is possible change all that to set-based methodology. But, like all development efforts, you would need to weigh the cost to the benefit. If you're happy with the results and the performance then it probably isn't worth changing. But if this process is a thorn in your side because of it's lack of reliability or performance then it may be worth the effort. Let us know if you want help with handling the encryption logic...Be One with the OptimizerTG |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-15 : 12:16:21
|
| Man, you hit the nail on the head. Currently its a real battle here weighing the cost to the benefit as we struggle through these trying economic times. But here is where my head is at the moment.Since 2001 I've carried the title IT Manager, meaning I've been the manager of a group of developers. Initially we were tasked with the development of one application using VB6 as the front end and SQL 2000 as the backend. I did quite a lot of the SQL development, nearly none of the VB6. In 2005 we were granted a special expenditure from the Legistature to increase our development efforts and implement an entire suite of accounting applications. This meant we were under the gun and had a lot of ground to cover. It was quick to copy and paste SQL code, good and bad. Most of the previous and present-day developers I've had working for me were top notch working the front end but I'm finding more and more they really didn't do a good job with the SQL code they created. A lot of code works good in Development and even in Simulation but when put under the load of a Production environment you begin to see the failings.Now, two things have happened. One, we lost most of our budget. We are not doing any new development instead being in a support and maintainence mode. Second, we have migrated to SQL 2008.I've told the powers that be that our applications are going to be in real trouble if we continue to maintain bad SQL code and in fact many places in our applications are beginning to suffer from performance. I've told them that before the migration to SQL 2008 is considered complete I want to examine every line to make sure we are doing things correctly and efficiently. For example, there are many sps using cursors and I'm trying to eliminate them as I can. But I don't know all the techniques, so I'm trying to learn.This started out trying to diagnose an error that was giving me fits. Yes, I almost always knew it was actually doing everything it was supposed to do but it was taking support time to make sure. And although it runs at off-peak time, has absolutley no impact on the performance of the applications and is basically a simple routine it now has given me the opportunity to explore and practice some new techiques in an area of no risk.I figure if I can modify this routine and make it better the techniques used will be useful in multiple other areas.I will leave the encryption as is for a couple of reasons. It is built into a function that is called from several places. I'm able to lock down this function so that many developers don't know exactly what it is doing. They call it and get the result, end of story. The fewer people that know the exact alogrithm used the better.I'm still planning on testing your coding change but so far today has been a bit busy. I'll keep you updated. |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-17 : 10:48:22
|
| Okay, it works and the results are very close to what they were with the old routine. Let me know if I've still got questionable techniques. Thanks.ALTER procedure [dbo].[update_wasp_test] ascreate table #wasp_proc (ssn char(9) ,agency char(3) ,isTerminated bit ,firstname varchar(75) ,lastname varchar(75) ,user_name_enc varchar(32) ,[user] varchar(75) ,new_user_name_enc varchar(32));with offset (w_id, offset, w_data) as( select w_id ,case when left(w_data,1) = 'T' then 0 else 1 end ,w_data from wasp_proc ),parse (w_id, [action],[agency],[ssn],[value]) as( select w_id ,substring(w_data, 1, 1+offset) ,substring(w_data, 2+offset, 3) ,substring(w_data, 5+offset, 9) ,substring(w_data, 14+offset, 75) from offset ),final (ssn,agency,isTerminated,firstname,lastname,[user]) as( select ssn ,max(agency) agency ,max(case when action = 'T' then 1 else 0 end) isTerminated ,max(case when action = 'CF' then [value] when action = 'T' then substring([value],1, isNull(nullif(charindex(' ', [value]),0),75)-1) end) FirstName ,max(case when action = 'CL' then [value] when action = 'T' then replace(substring([value],isNull(nullif(charindex(' ', [value]),0)+1,1), 75),'-'+agency,'') end) LastName ,max(case when action in ('T','CO') then [value] end) as [user] from parse group by ssn)insert #wasp_proc (ssn ,agency ,isTerminated ,firstname ,lastname ,user_name_enc ,[user] ,new_user_name_enc)select ssn ,agency ,isTerminated ,firstname ,lastname ,dbo.fn_enc([user]) as user_name_enc ,[user] ,dbo.fn_enc(rtrim(firstname)+' '+RTRIM(lastname)+'-'+agency) as new_user_name_encfrom finalinsert into wasp_logselect GETDATE(),t.agency,au.user_id,t.[user],t.user_name_enc,'','','','','USER NOT FOUND',''from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere au.user_id is nullinsert into wasp_logselect GETDATE(),t.agency,au.user_id,t.[user],t.user_name_enc,'','','','','TERMINATION','adm_app DELETED'from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere t.isTerminated = 1 and au.user_id is not nulldelete adm_app where user_id in(select au.user_idfrom #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere t.isTerminated = 1 and au.user_id is not null)insert into wasp_logselect GETDATE(),t.agency,au.user_id,t.[user],t.user_name_enc,t.firstname,t.lastname,rtrim(t.firstname)+' '+rtrim(t.lastname)+'-'+t.agency,t.new_user_name_enc,'','NOT PROCESSED'from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere t.isTerminated = 0 and au.user_id is not nulland t.new_user_name_enc = au.user_name_encinsert into wasp_logselect GETDATE(),t.agency,au.user_id,t.[user],t.user_name_enc,t.firstname,t.lastname,rtrim(t.firstname)+' '+rtrim(t.lastname)+'-'+t.agency,t.new_user_name_enc,'NAME CHANGED','adm_user UPDATED'from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere t.isTerminated = 0 and au.user_id is not nulland t.new_user_name_enc <> au.user_name_encupdate PCard.dbo.pcard_user set first_name = t.firstname, last_name = t.lastname, user_name = RTRIM(t.firstname)+' '+RTRIM(t.lastname) from #wasp_proc t left outer join adm_user au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_enc and au.user_id = pcard_user.user_id update Pmtsvcs.dbo.pmtsvcs_user set first_name = t.firstname, last_name = t.lastname, user_name = RTRIM(t.firstname)+' '+RTRIM(t.lastname) from #wasp_proc t left outer join adm_user au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_enc and au.user_id = pmtsvcs_user.user_idupdate adm_user set first_name = t.firstname, last_name = t.lastname, user_name_enc = dbo.fn_enc(RTRIM(t.firstname)+' '+rtrim(t.lastname)+'-'+t.agency) from #wasp_proc t left outer join adm_user au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_encdrop table #wasp_procProud member of BRONCO NATION! |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-17 : 16:58:00
|
Couple things: it is good practice to use explicit column lists for your INSERT statement insert into wasp_log ( <column List> )select <columns and expressions> you could combine all your inserts to the log table into a single statement - remove the WHERE clauses and build that criteria into CASE statements: case when au.user_name_enc is null then 'USER NOT FOUND' when t.isTerminated = 1 then 'TERMINATION' when t.isTerminated = 0 and au.user_id is not null then 'NOT PROCESSED' etc... end, ''from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_enc finally - when you post your code here use code tags to retain any formatting you used:[code]<code block>[/code]Be One with the OptimizerTG |
 |
|
|
sfalter
Starting Member
15 Posts |
Posted - 2010-11-18 : 11:52:55
|
I knew you were going to say that!! So, I think I've got it now. Again, thanks for your help as well as your patience. I think I'm beginning to grasp these concepts, can't wait to start wading into other areas now to do some good clean up.create table #wasp_proc (ssn char(9) ,agency char(3) ,isTerminated bit ,firstname varchar(75) ,lastname varchar(75) ,user_name_enc varchar(32) ,[user] varchar(75) ,new_user_name_enc varchar(32));with offset (w_id, offset, w_data) as( select w_id ,case when left(w_data,1) = 'T' then 0 else 1 end ,w_data from wasp_proc ),parse (w_id, [action],[agency],[ssn],[value]) as( select w_id ,substring(w_data, 1, 1+offset) ,substring(w_data, 2+offset, 3) ,substring(w_data, 5+offset, 9) ,substring(w_data, 14+offset, 75) from offset ),final (ssn,agency,isTerminated,firstname,lastname,[user]) as( select ssn ,max(agency) agency ,max(case when action = 'T' then 1 else 0 end) isTerminated ,max(case when action = 'CF' then [value] when action = 'T' then substring([value],1, isNull(nullif(charindex(' ', [value]),0),75)-1) end) FirstName ,max(case when action = 'CL' then [value] when action = 'T' then replace(substring([value],isNull(nullif(charindex(' ', [value]),0)+1,1), 75),'-'+agency,'') end) LastName ,max(case when action in ('T','CO') then [value] end) as [user] from parse group by ssn)insert #wasp_proc (ssn ,agency ,isTerminated ,firstname ,lastname ,user_name_enc ,[user] ,new_user_name_enc)select ssn ,agency ,isTerminated ,firstname ,lastname ,dbo.fn_enc([user]) as user_name_enc ,[user] ,dbo.fn_enc(rtrim(firstname)+' '+RTRIM(lastname)+'-'+agency) as new_user_name_encfrom finalinsert into wasp_log (log_date ,agency_code ,user_id ,old_user ,old_ency ,new_first ,new_last ,new_user ,new_ency ,user_status ,process_status)select GETDATE(), t.agency, au.user_id, t.[user], t.user_name_enc, t.firstname, t.lastname, rtrim(t.firstname)+' '+rtrim(t.lastname)+'-'+t.agency, t.new_user_name_enc, case when au.user_id is null then 'USER NOT FOUND' when t.isTerminated = 1 and au.user_id is not null then 'TERMINATION' when t.isTerminated = 0 and au.user_id is not null and t.new_user_name_enc <> au.user_name_enc then 'NAME CHANGED' else '' end, case when t.isTerminated = 1 and au.user_id is not null then 'adm_app DELETED' when t.isTerminated = 0 and au.user_id is not null and t.new_user_name_enc = au.user_name_enc then 'NOT PROCESSED' when t.isTerminated = 0 and au.user_id is not null and t.new_user_name_enc <> au.user_name_enc then 'adm_user UPDATED' else '' end from #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encdelete adm_app where user_id in(select au.user_idfrom #wasp_proc tleft outer join adm_user au on au.user_name_enc = t.user_name_encwhere t.isTerminated = 1 and au.user_id is not null)update PCard.dbo.pcard_user set first_name = t.firstname, last_name = t.lastname, user_name = RTRIM(t.firstname)+' '+RTRIM(t.lastname) from #wasp_proc t left outer join adm_user au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_enc and au.user_id = pcard_user.user_id update Pmtsvcs.dbo.pmtsvcs_user set first_name = t.firstname, last_name = t.lastname, user_name = RTRIM(t.firstname)+' '+RTRIM(t.lastname) from #wasp_proc t left outer join adm_user au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_enc and au.user_id = pmtsvcs_user.user_idupdate adm_user set first_name = t.firstname, last_name = t.lastname, user_name_enc = dbo.fn_md5(RTRIM(t.firstname)+' '+rtrim(t.lastname)+'-'+t.agency) from #wasp_proc t left outer join adm_user_test au on au.user_name_enc = t.user_name_enc where t.isTerminated = 0 and au.user_id is not null and au.user_name_enc = t.user_name_enc and t.new_user_name_enc <> au.user_name_encdrop table #wasp_procProud member of BRONCO NATION! |
 |
|
|
TG
Master Smack Fu Yak Hacker
6065 Posts |
Posted - 2010-11-18 : 14:44:42
|
| You're welcome - welcome to your new set-based life :)One last comment regarding user defined functions (fn_enc). Scalar functions can be very helpful and encapsulate code nicely but you should be careful when using them in a SELECT list. Depending on what they are doing you could loose the benefit of the set-based methodology. If you are not returning many rows like for server side paging (20 rows at a time) it may not make any big difference. But if you are inserting millions of rows then it could result in slow, row-by-row processing. Sometimes you can write that code as a set-based, table-valued function and then JOIN the function to your query as you would a table. That way a column from that table valued function can be returned instead of running the scalar function once for every row.But baby steps - And good job!Be One with the OptimizerTG |
 |
|
|
|
|
|
|
|