Debug output in T-SQL - tsql

When debugging T-SQL, is there something like Javascript's alert(); function or console.log I can use to output values when testing and debugging SQL scripts or stored procedures?

You can use PRINT to output messages to log but I personally prefer using RAISERROR with low severity because PRINT output is not always printed to screen immediately. Especially in long runnig SP's. On the other hand something like this prints immediately:
RAISERROR ('My Message', 10, 1)
Do not be fooled by the name ERROR, an error with severity 10 does no harm.
As for CTE, I think you are having a problem with self referencing Common Table Expressions. But you should know that there is no way to insert a PRINT statement into the execution of a recursive CTE.
To debug those I usually add an extra "Iteration Index" column to the result set that is incremented with each iteration. Also some other columns to help assess the situation. When examined with the rest of the resultset, it usually gives good insight. Something like the IDX col down. Other columns help me examine join conditions to see what was wrong:
WITH x AS (
SELECT 1 AS IDX, A._ID as ID_A, NULL as ID_B
FROM MYTABLE A
WHERE A._ID = 6
UNION ALL
SELECT X.IDX + 1, A._ID, B._ID
FROM MYTABLE B INNER JOIN X ON B._ID = X._ID + 1
WHERE B._ID < 20
)
SELECT *
FROM X

Yes, it's called PRINT. See here:
http://msdn.microsoft.com/en-us/library/ms176047.aspx

I use the instruction "RAISERROR" with the hint "WITH NOWAIT" like below:
RAISERROR('My message here', 10, 1) WITH NOWAIT
This instruction displays the message in time.

PRINT statement helps. Instead of PRINT giving output to result pane I sometimes insert the debug output to a table.
Newer version of SQL (2008 and 2008R2) has debug option. Not as solid as debugging a c# project in Visual Studio but quite good. You can go step by step and also create variable watchlist.

Related

DB2 trigger illegal token

Fairly new to DB2 sql, so forgive my ignorance :)
I have a trigger with a condition inside. I want to then insert some params depending on the condition.. Here it is:
I've looked at DB2 documentation for triggers and also for if statements, and at least to my eyes it appears to comply with it, however i get a -104 error (Illegal symbol token) on the insert line.
The insert works fine provided i use values not from 'N'.
OK, it works if i have nothing in the if then statement.. but only if i have nothing!
Thanks
My guess would be that DB2 is confused by your statement terminators. You use a semicolon to terminate the CREATE TRIGGER statement, but at the same time you use the same terminator inside the CREATE TRIGGER statement, after the INSERT.
In whatever client you use to execute your code, redefine the statement terminator to something else and place that terminator at the end of CREATE TRIGGER, after END ID. For example, if you use the command line processor, save this to a file trig.sql:
CREATE OR REPLACE TRIGGER AUTO_INSERT_DEPO_NOMINEE
AFTER INSERT ON CA_ENTITLEMENT
REFERENCING NEW AS N
FOR EACH ROW
IF NOT EXISTS (SELECT D.DEPO_CD FROM DEPO D WHERE D.DEPO_CD = N.DEPO_CD)
THEN
INSERT INTO DEPO (DEPO_CD, DEPO_NME, BRANCH_CD, AUTO_GENERATED)
VALUES(N.DEPO_CD, NULL, N.BRANCH_CD, 'Y');
END IF#
then run it, specifying "#" as the statement terminator:
db2 -td# -f mytrig.sql

execute command in while loop

I have a postgres function which runs the following loop
while x<=colnum LOOP
EXECUTE
'Update attendrpt set
slot'||x||' = pres
from (SELECT branch, semester, attend_date , div, array_to_string(ARRAY_AGG(first_name||':'||alias_name||':'||lect_type||':'||
to_char(present,'99')),';')
As pres
from attend1 where lecture_slot_no ='||x||'
group by branch, semester, attend_date , div ) j
where attendrpt.branch=j.branch and attendrpt.semester=j.semester
and attendrpt.attenddate=j.attend_date and attendrpt.div=j.div;';
`x:=x+1;
END LOOP;`
The problem here is it is conflicting the single quotes closing in query and the execute command.Is there anyway to solve this.
Thanks in advance.
Quote your function definition with dollar-quoting (like $BODY$ or just $$) as per the manual.
Use execute ... using instead of string substitution. For substituting identifiers use the %I format specifier from the format function.
If you absolutely must use || string concatenation, say if you're on some ancient version of PostgreSQL, you need to use the quote_literal and quote_ident functions to avoid issues with quoting and potential security problems.
Beyond that, it looks like the whole approach is completely unnecessary; you're doing something that looks like it can be done in simple SQL.

Unexpected behavior in TSQL trigger using cursor: AND operator with values 1 AND 0 evaluates to true

I have been trying to debug some questionable database transactions produced by a trigger and when stepping through the T-SQL have encountered unexpected results. After obtaining values from the cursor via FETCH NEXT FROM Updated_Cursor , I enter a while loop and then for each row fetched from the cursor I evaluate two variables to determine whether an insertion will be made after some processing as follows:
WHILE ##FETCH_STATUS = 0
BEGIN
IF (#first_indicator > 0 AND #second_indicator >0)
BEGIN
--processing and insert occurs here
In debug mode, stepping through the code, I can see that when the value of #first_indicator=1 and #second_indicator=0 this condition is evaluating to true which does not make sense to me. It is resulting in duplicate and erroneous rows being inserted. The two variables are bit datatype, which I feel may be relevant, but I am lost as to why this is happening.
When pulling your code out of the cursor like so:
DECLARE #f BIT = 1
DECLARE #s BIT = 0
IF(#f>0 AND #s>0) PRINT 'GH';
It works as expected and does not print. Are you sure that you are looking at the right variables at the right time when the if statement gets executed?
Also, the two IF statements you mention in your comment are not equivalent. Therefore I am not exactly sure what your actual question is.

SQLPlus 's weird reaction during DML statements execution

Today i was executing DML statements from sql file in sqlplus, oracle 10.2, i found something weird which is actually a question "Enter value for hamburger:". See attached
and ending of question "Enter value for XXX" kept change with intervals. i mean after few seconds i found statement "Enter value for mcdonald"....
I want to know is it normal with sqlplus ????
i have tried to execute DML statement by giving location of sql file in sqlplus.
SQL>#/tmp/myDir/dmls.sql;
An Exemplary statement from sql file is
Insert into MYSCHEMA.MYTABLE (ID,DIX_DIR_ID,DIX_AGL,DIX_XML_INLINE) values (23202,1100080319000620471,'directory','<values>
<dir_class_title>Person</dir_class_title>
</values>
');
You most certainly have an ampersand in your statement.
When SQL*Plus encounters an ampersand, it tries to replace it with what it is defined to. If it is undefined, it prompts for a value:
This is a statment without ampersand:
SQL> select 'foo' from dual;
'FO
---
foo
Now, another statement with an ampersand. The value for foo is not (yet) defined, so it prompts for one:
SQL> select '&foo' from dual;
Enter value for foo: bla
old 1: select '&foo' from dual
new 1: select 'bla' from dual
'BL
---
bla
Now, foo is defined to be bar:
SQL> define foo=bar
The select statement (with &foo) returns bar:
SQL> select '&foo' from dual;
old 1: select '&foo' from dual
new 1: select 'bar' from dual
'BA
---
bar
See also DEFINE and Defining Substitution Variables
If you want to turn that behavior off, do as
SQL> set define off
Edit: changed set define= to set define off as per Adam Musch's suggestion.

TSQL Concatenation

I often need to concatenate fields in TSQL...
Two issues TSQL forces you to deal with when using the '+' operator are Data Type Precedence and NULL values.
With Data Type Precedence, the problem is conversion errors.
1) SELECT 1 + 'B' = Conversion ERROR
2) SELECT 1 + '1' = 2
3) SELECT '1' + '1' = '11'
In 2), the varchar '1' is implicitly converted to an int, and the math works. However, in 1), the int 1 is NOT implicitly converted to a varchar. This is where DTP is (IMO) getting in the way. Essentially, it favors Math functions over String functions. I Wish :-) that DTP wasn't even a consideration in this case -- why wouldn't the '+' operator be configured so that the operation could favor success over specific data-types? I wouldn't mind if it still favored MATH over String functions when possible -- but why doesn't it favor String functions over Errors? (The only way to be successful in 1) is to treat it as a string function -- so it's not like there's any ambiguity there.) Somebody at Microsoft thought that throwing an error in 1) would be more valuable to the programmer than treating the '+' as a string function. Why? And why didn't they provide a way to override it? (Or did they...that's really the heart of my question.) SET STRING_PREFERENCE ON would have been nice! :-P
In order to deal with this, you have to do more work -- you have to explicitly convert the 1 to a varchar, using any number of different string functions -- typically CAST/CONVERT, but also many others (like LTRIM()) will work.
Conversions become work-intensive when you deal with table fields when you don't know the data-type. This might work:
SELECT 'Fall ' + ' (' + [Term] + ')' -- Output: Fall (2011)
But then again, it might not. It just depends on what data-type of [Term] is. And to complicate that, the dba might change the dataype at some point without telling anyone (because it came as part of a big upgrade package once the vendor finally realized that there are only ever numbers stored in the [Term] field, or whatever reason).
So if you want to be a boyscount, you do this:
SELECT 'Fall ' + ' (' + LTRIM([Term]) + ')'
So now I'm running this LTRIM function every time, even though it might not be necessary, because I don't know the data-type of [Term] (OK -- I can look that up, but that's almost like work, and I don't like interruptions while I'm coding :-P *grump), and also, I don't know that the data-type will never change.
The second issue you have to confront with TSQL concatenation is how to deal with NULL values. For example, this would fail:
SELECT NULL + 'B'
So you need to do this:
SELECT 'Fall ' + ' (' + LTRIM(ISNULL([Term],'')) + ')'
What a pain -- I wish I could just do this:
SELECT 'Fall ' + ' (' + [Term] + ')'
So I'm wondering if there are any (TSQL) ways to avoid having to do explicit data-type conversions and null checks on every field where I have to ensure the '+' operator behaves itself as I need it to.
Thanks!
EDIT
#a1ex07 came up with a great answer for working around the NULL issue (SET CONCAT_NULL_YEILDS_NULL OFF), but as I looked into it, it appears to be problematic as far as forcing stored procedures to re-compile every time they're executed.
SQL Server 2012 does have the CONCAT function which addresses all the issues you raise.
A good summary of the functionality is provided here by SQL Menace
CONCAT takes a variable number of string arguments and concatenates
them into a single string. It requires a minimum of two input values;
otherwise, an error is raised. All arguments are implicitly converted
to string types and then concatenated. Null values are implicitly
converted to an empty string. If all the arguments are null, then an
empty string of type varchar(1) is returned. The implicit conversion
to strings follows the existing rules for data type conversions
UPDATE
You can use CONCAT_NULL_YIELDS_NULL to specify whether NULL + 'txt' results NULL.
Microsft says that CONCAT_NULL_YIELDS_NULL will not work in further versions of SQL Server, but there is still an option to set it through sp_dboption procedure . But probably it's better to use ISNULL as you mentioned in the question.
Try this:
/* 1 */ SELECT cast(1 as varchar) + 'B'; /* = 1B */
/* or */ SELECT convert(varchar, 1) + 'B'; /* = 1B */
/* 2 */ SELECT cast(1 as varchar) + '1'; /* = 11 */
/* 3 */ SELECT '1' + '1'; /* = 11 */
/* or */ SELECT CONVERT(VARCHAR, '1') + CONVERT(VARCHAR, '1');
--NULL value:
DECLARE #A AS VARCHAR(10);
SET #A = NULL;
SELECT ISNULL(#A, '') + 1; /* = 1 */
There is no answer to this for 2005 or 2008. Concatenation without explicit conversions and null checks simply isn't possible.
It looks like the next version of SQL-Server will have a CONCAT function (thanks #Martin) which sounds like exactly what I'm looking for. The downside though is that it will probably be at least a handful of years before my institution decides to upgrade to that version, since they're pretty shy about being early adopters, especially when it comes to Microsoft.
There is a shortcut for the NULL checks right now (CONCAT_NULL_YIELDS_NULL -- thanks #a1ex07), however, using that has a pretty big penalty (re-compiles the procedure every time it is executed), not to mention Microsoft isn't planning to support it in future versions of SQL-Server.