Trigger to record SQL when constraint error encountered

I am trying to get a trigger to work when a user gets a constraint error.    It is supposed to record the SQL being executed by the user.  

The trigger is working fine until I try to combine the multiple lines of the  SQL statement into a variable so that it's all one line.

But when I put in the  line to do the combine, only the first two utl_file.put_line commands performed prior to the loop will work.  All others fail.  

Here is my combine command:      sql_stmt_text := sql_stmt_text || l_text(i);

Here is the trigger:

create or replace trigger test_trigger
after servererror on database

declare

l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;    

begin

v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_OUTPUT','failing_SQL_Stmt.txt','W');                  


if ( is_servererror(0001) )
then
  utl_file.put_line(v_output_file1,'--------------------');
  utl_file.put_line(v_output_file1,'statement causing error: ');
 
  l_n := ora_sql_txt( l_text );

  for i in 1 .. nvl(l_n,0) loop

    -- this statement works when it is the only one in the loop.
    -- also all following utl_file.put_line commands are successful.
    utl_file.put_line(v_output_file1,l_text(i));

    -- when I include this statement, none of the utl_file.put_line commands work except
    --  for the two just before the loop.  
    sql_stmt_text := sql_stmt_text || l_text(i);

  end loop;

  utl_file.put_line(v_output_file1,sql_stmt_text);

  utl_file.put_line(v_output_file1,'error text: ');

  for i in 1 .. ora_server_error_depth
  loop
    utl_file.put_line(v_output_file1,ora_server_error_msg(i));
  end loop;
    utl_file.put_line(v_output_file1,'--------------------');

end if;

utl_file.fclose_all;

end;
/
LVL 1
Julie KurpaSr. Systems ProgrammerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

slightwv (䄆 Netminder) Commented:
What version of Oracle are you using?

Works for me using 18.0.

I modified your PUT_LINES to add location1 and location2 tothem so I know what wrote what.

create or replace trigger test_trigger
after servererror on database

declare

l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;    

begin

v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_OUTPUT','failing_SQL_Stmt.txt','W');                  

if ( is_servererror(0001) )
then
  utl_file.put_line(v_output_file1,'--------------------');
  utl_file.put_line(v_output_file1,'statement causing error: ');
 
  l_n := ora_sql_txt( l_text );


  for i in 1 .. nvl(l_n,0) loop

    -- this statement works when it is the only one in the loop.
    -- also all following utl_file.put_line commands are successful.
    utl_file.put_line(v_output_file1,'Location1: ' || l_text(i));

    -- when I include this statement, none of the utl_file.put_line commands work except
    --  for the two just before the loop.  
    sql_stmt_text := sql_stmt_text || l_text(i);

  end loop;

  utl_file.put_line(v_output_file1,'Location2: ' || sql_stmt_text);

  utl_file.put_line(v_output_file1,'error text: ');

  for i in 1 .. ora_server_error_depth
  loop
    utl_file.put_line(v_output_file1,ora_server_error_msg(i));
  end loop;
    utl_file.put_line(v_output_file1,'--------------------');

end if;

utl_file.fclose_all;

end;
/

show errors

create or replace directory SQL_STMT_OUTPUT as 'C:\TEMP';

drop table tab1 purge;
create table tab1(col1 char(1) primary key);

insert into tab1 values('a');
insert into tab1 values('a');

Open in new window


My test run output:
SQL> @q

Trigger created.

No errors.

Directory created.


Table dropped.


Table created.


1 row created.

insert into tab1 values('a')
*
ERROR at line 1:
ORA-00001: unique constraint (BUD.SYS_C0016150) violated

Open in new window


My file contents:
C:\TEMP>type failing_SQL_Stmt.txt
--------------------
statement causing error:
Location1: insert into tab1 values('a')
Location2: insert into tab1 values('a')
error text:
ORA-00001: unique constraint (MYUSER.SYS_C0016150) violated

--------------------

Open in new window

Julie KurpaSr. Systems ProgrammerAuthor Commented:
Thanks Slightwv.  :)

I'm using Oracle 11g running on Oracle LInux.  

Perhaps it would help if I included the output without the "offending" line and then with it so you see what I see.   Am putting it together now.
Julie KurpaSr. Systems ProgrammerAuthor Commented:
In breaking down the changes, I see that it's actually the "utl_file.put_line(v_output_file1,sql_stmt_text);"  that is causing the problem, not the "sql_stmt_text := sql_stmt_text || l_text(i);".

Here is the output WITHOUT the "utl_file.put_line(v_output_file1,sql_stmt_text);"

--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column2,column3,column4,column5,
column6,column7,column8,column9,column10,column11,column12,colum
m13) VALUES (1111,2222,3333,4444,5555,6666,7777,8888,9999,1010,1
111,1212,1313)
error text:
ORA-00001: unique constraint (MYUSER.PK_TAB1) violated


This is the output when  I include the "utl_file.put_line(v_output_file1,sql_stmt_text);" statement. Notice it doesn't write anything after it's supposed to writethe contents of varable sql_stmt_text:

--------------------
statement causing error:
INSERT INTO myuser.tab1(column1,column2,column3,column4,column5,
column6,column7,column8,column9,column10,column11,column12,colum
m13) VALUES (1111,2222,3333,4444,5555,6666,7777,8888,9999,1010,1
111,1212,1313)


I tried sending the contents of variable sql_stmt_text to different file altogether.  
When doing that, I get the full constraint information written to the first location but never the content of the sql_stmt_text variable in the 2nd file. The 2nd location stays blank.
Powerful Yet Easy-to-Use Network Monitoring

Identify excessive bandwidth utilization or unexpected application traffic with SolarWinds Bandwidth Analyzer Pack.

slightwv (䄆 Netminder) Commented:
I can only go with what I can personally test.  The code I posted worked for me.

If you want me to run some other test, post the code you wish me to test.  I don't have access to an 11g database any more but can test on 12.2 right now and 18c later today.

>>Here is the output WITHOUT the "utl_file.put_line(v_output_file1,sql_stmt_text);

If you are getting the output you want, what are you trying to accomplish by changing it?  I'm not understanding why you need the SQL on a single line.  What happens when you get SQL larger than 32k?
Julie KurpaSr. Systems ProgrammerAuthor Commented:
It seems your code is exactly like mine so I don't really have any changes to make.  If it runs in 12.2 then I'm not sure what else to try.


I wanted to get the SQL into a single line because I plan to extract certain elements from it and use it in a procedure.  If it's wrapping like it is, then certain elements I need may be split between lines.
slightwv (䄆 Netminder) Commented:
OK, I think I've been able to reproduce this using longer SQL.  Let me dig into this a little more.
slightwv (䄆 Netminder) Commented:
Took me a while to remember this:  The FOPEN has a max_linesize parameter that defaults to 1024.

You need to specify a larger value:
https://docs.oracle.com/en/database/oracle/oracle-database/18/arpls/UTL_FILE.html#GUID-DF14ADC3-983D-4E0F-BE2C-60733FF58539

I also cleaned up the code.  There isn't a reason to create the concatenated string.  Just use PUT instead of PUT_LINE.  Just issue a PUT_LINE outside the loop to finish off the line.

Here is my modified test case:
create or replace trigger test_trigger
after servererror on database

declare

l_text ora_name_list_t;
l_n number;
v_output_file1 utl_file.file_type;    

begin

v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_OUTPUT','failing_SQL_Stmt.txt','W',32767);                  

if ( is_servererror(0001) )
then
  utl_file.put_line(v_output_file1,'--------------------');
  utl_file.put_line(v_output_file1,'statement causing error: ');
 
  l_n := ora_sql_txt( l_text );

  for i in 1 .. nvl(l_n,0) loop
    utl_file.put(v_output_file1,l_text(i));
  end loop;
  utl_file.put_line(v_output_file1,null);

  utl_file.put_line(v_output_file1,'error text: ');

  for i in 1 .. ora_server_error_depth
  loop
    utl_file.put_line(v_output_file1,ora_server_error_msg(i));
  end loop;
    utl_file.put_line(v_output_file1,'--------------------');

end if;

utl_file.fclose(v_output_file1);

end;
/

show errors

create or replace directory SQL_STMT_OUTPUT as '/tmp';

drop table tab1 purge;
create table tab1(col1 varchar2(4000) primary key);

insert into tab1 values('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
insert into tab1 values('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Julie KurpaSr. Systems ProgrammerAuthor Commented:
I really appreciate your help.

On a whim, I directed that variable to a table instead of to a file and it seems to work.  The entire SQL is being written into one column.  This is where I eventually wanted to end up but was just writting to the file so I could see what I was getting.

Here's the adjusted code.  

create or replace trigger test_trigger
after servererror on database

declare

l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(32767);
v_output_file1 utl_file.file_type;    

begin

v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_OUTPUT','failing_SQL_Stmt.txt','W');                  


if ( is_servererror(0001) )
then
  utl_file.put_line(v_output_file1,'--------------------');
  utl_file.put_line(v_output_file1,'statement causing error: ');
 
  l_n := ora_sql_txt( l_text );

  for i in 1 .. nvl(l_n,0) loop

    utl_file.put_line(v_output_file1,l_text(i));

    sql_stmt_text := sql_stmt_text || l_text(i);

  end loop;

  INSERT INTO myuser.sql_event VALUES (sql_stmt_text);

  utl_file.put_line(v_output_file1,'error text: ');

  for i in 1 .. ora_server_error_depth
  loop
    utl_file.put_line(v_output_file1,ora_server_error_msg(i));
  end loop;
    utl_file.put_line(v_output_file1,'--------------------');

end if;

utl_file.fclose_all;

end;
/
Julie KurpaSr. Systems ProgrammerAuthor Commented:
oh I just saw your post.  am reading it now.
Julie KurpaSr. Systems ProgrammerAuthor Commented:
That worked great slighwv!  You are wonderful!

I set the FOPEN size to 32767 and I'm getting the full SQL text on one line in the file.
Now I have many options on how to handle the rest of my project.
Julie KurpaSr. Systems ProgrammerAuthor Commented:
Here's the working product with the writing of the SQL on all one line to the output file outside the loop.

create or replace trigger test_trigger
after servererror on database

declare

l_text ora_name_list_t;
l_n number;
sql_stmt_text varchar2(10000);
v_output_file1 utl_file.file_type;    

begin

v_output_file1 := UTL_FILE.FOPEN('SQL_STMT_OUTPUT','failing_SQL_Stmt.txt','W',32767);                  


if ( is_servererror(0001) )
then
  utl_file.put_line(v_output_file1,'--------------------');
  utl_file.put_line(v_output_file1,'statement causing error: ');
 
  l_n := ora_sql_txt( l_text );

  for i in 1 .. nvl(l_n,0) loop

    utl_file.put_line(v_output_file1,l_text(i));

    sql_stmt_text := sql_stmt_text || l_text(i);

  end loop;

  -- write the combined SQL  to a table
  INSERT INTO myuser.sql_event VALUES (sql_stmt_text);

  -- write the combined SQL to the file
  utl_file.put_line(v_output_file1,'error text: ');

  for i in 1 .. ora_server_error_depth
  loop
    utl_file.put_line(v_output_file1,ora_server_error_msg(i));
  end loop;
    utl_file.put_line(v_output_file1,'--------------------');

end if;

utl_file.fclose_all;

end;
/
slightwv (䄆 Netminder) Commented:
>>SQL on all one line to the output file outside the loop.

Why when it isn't necessary?
Julie KurpaSr. Systems ProgrammerAuthor Commented:
Just to show it as part of the solution.  I won't continue to do it now that I'm writing it to a table.
Julie KurpaSr. Systems ProgrammerAuthor Commented:
slightwv didn't have to do further research when his SQL worked fine.  Went the extra mile to reproduce the problem and found the solution.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Query Syntax

From novice to tech pro — start learning today.