SQL Server: Why does adding a null to a variable not cause an error? - sql-server-2012

I have a stored procedure that has a loop based on a counter. When the counter becomes NULL the loop ends without any error. Why doesn't SQL Server at least display a warning or error message like other programming languages?
Here is a code sample which exhibits the problem:
DECLARE #MasterCount int = 0;
DECLARE #Count int; -- initialized to NULL by SQL Server
PRINT 'Starting'
IF (#MasterCount IS NULL)
PRINT '#MasterCount IS NULL';
ELSE
PRINT '#MasterCount ' + CAST(#MasterCount AS varchar(10))
IF (#Count IS NULL)
PRINT '#Count IS NULL';
WHILE (#MasterCount IS NOT NULL)
BEGIN
SET #MasterCount += #Count;
IF ##ERROR <> 0 PRINT 'Error occured!'
PRINT 'Loop #Count ' + CAST(#Count AS varchar(10))
SET #Count -= 1;
END
IF ##ERROR <> 0 PRINT 'Error occured!'
IF (#MasterCount IS NULL)
PRINT '#MasterCount IS NULL';
ELSE
PRINT '#MasterCount ' + CAST(#MasterCount AS varchar(10))
PRINT 'Ending'
Produces the following output:
Starting
#MasterCount 0
#Count IS NULL
#MasterCount IS NULL
Ending

It doesn't raise an error because this is defined, documented behaviour.
If you have two apples and you know the weight of only one then it makes sense that the weight of both of them added together is not known.
You can actually get a warning to appear if you slightly alter the formulation.
Instead of
SET #MasterCount += #Count;
You could use
SELECT #MasterCount = SUM(C)
FROM (VALUES(#Count),
(#MasterCount )) V(C);
In which case it gives
Warning: Null value is eliminated by an aggregate or other SET
operation.
This does change the semantics however. As the null value was entirely ignored you would end up with #MasterCount simply being assigned back its original value rather than being set to null in your scenario.

Related

Breakline in Raiseerror

is there anyway to breakline and continue on next line in RaiseError?
<br/> and /n aren't working
Below is my code:
BEGIN
BEGIN TRY
SELECT 16/0
END TRY
BEGIN CATCH
WHILE(#Count != 0)
BEGIN
SET #MaterialName = (SELECT Material FROM #T WHERE Quantity = 0 AND ID = #Count)
SET #MSG = 'Material %s was not offered.'
RAISERROR(#MSG,16,1,#MaterialName);
SET #Count = #Count - 1
END
END CATCH
END
I dont want to make changes in the data access layer, we only support web, not window app. I want each loop msg to be printed on next line using sql only.
Is it possible?
if you include the line break in the text it will work.
SET #MSG = 'Material %s was not offered.
'
Note that the end quote is on a new line.
I'm no pro in sql but I think this will help
Char(10)
Inserts a new line break a good guide about it is here: https://www.itsupportguides.com/knowledge-base/sql-server/sql-how-to-insert-new-lineline-break-in-string/
I've also seen \n used before but I don't know if that can be used in your circumstance

Algorithm for auto generated series number in sql

I want to make an algorithm for generate next series number by specified last series number in sql like below:
Last Number Next Number
> AAAA095 AAAA096
> AAAA999 AAAB001
> AAAB001 AAAB002
> AAAZ999 AABA001
After some try, Finally i got an algorithm & create it to SQL Scalar-valued function for this question as below
CREATE FUNCTION GetNextSeries ( #lastSeriesNo VARCHAR(8))
RETURNS VARCHAR(8)
AS
BEGIN
DECLARE #nextSeriesNo VARCHAR(8)
DECLARE #CHAR1 CHAR=SUBSTRING(#lastSeriesNo,1,1)
DECLARE #CHAR2 CHAR=SUBSTRING(#lastSeriesNo,2,1)
DECLARE #CHAR3 CHAR=SUBSTRING(#lastSeriesNo,3,1)
DECLARE #CHAR4 CHAR=SUBSTRING(#lastSeriesNo,4,1)
DECLARE #n INT=SUBSTRING(#lastSeriesNo,5,3)
SET #n = #n + 1
IF(#n>999)
BEGIN
SET #n=1
IF(#CHAR4<>'Z')
BEGIN
SET #CHAR4=CHAR(UNICODE(#CHAR4)+1)
END
ELSE IF(#CHAR3<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3=CHAR(UNICODE(#CHAR3)+1)
END
ELSE IF(#CHAR2<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3='A'
SET #CHAR2=CHAR(UNICODE(#CHAR2)+1)
END
ELSE IF(#CHAR1<>'Z')
BEGIN
SET #CHAR4='A'
SET #CHAR3='A'
SET #CHAR2='A'
SET #CHAR1=CHAR(UNICODE(#CHAR1)+1)
END
END
SET #nextSeriesNo=#CHAR1+#CHAR2+#CHAR3+#CHAR4+(CASE LEN(#n) WHEN 1 THEN '00' WHEN 2 THEN '0' ELSE '' END)+convert(VARCHAR(3),#n)
RETURN #nextSeriesNo
END

MS SQL scalar function to format datebased on language switch

I have created a scalar function that is supposed to spit out a date in a specific format based on a variable.
for some reason i get an error around the "else"
what am i doing wrong ?
CREATE FUNCTION [dbo].[fGetDateformat] (#datum datetime,#CNotation char(2))
/* accepts datum and CNotation
USAGE:
select fGetDateformat(datum, "EN" or "DE") */
returns varchar(25) AS
BEGIN
declare #ReturnStr varchar(25)
if #Cnotation = 'DE'
set language german
set #ReturnStr =
DATENAME(dd, #datum)+'. '+DATENAME(MM, #datum)+' '+ DATENAME(YEAR, #datum)
else
set #ReturnStr = DATENAME(mm, #datum)+' '+DATENAME(dd, #datum)+', '+ DATENAME(YEAR, #datum)
return #ReturnStr
END
GO
If a T-SQL block spans multiple lines, you have to enclose it in begin and end. For example, this won't work:
if 1=1
print 'One is one!'
print 'Yay'
else
print 'Huh?'
This will:
if 1=1
begin
print 'One is one!'
print 'Yay'
end
else
print 'Huh?'
Note that print 'Huh?' is still okay, since it is a single line.

Procedure stops when legacy, new error traps are next to each other

We have a bunch of old stored procedures with legacy style error trapping. I changed one the other day and included a newer TRY...CATCH block. The stored procedure just stopped after the TRY/CATCH and returned as though there were an error in the legacy block.
If I put a
SELECT NULL
in between the two everything works fine. Anyone know why this is happening?
--BEGIN NEW ERROR TRAP--
BEGIN TRY
Do stuff...
END TRY
BEGIN CATCH
END CATCH
--END NEW ERROR TRAP---
----------------- OLD SCHOOL TRAP BEGIN -----------------
SELECT #spERROR = ##ERROR ,
#spROWCOUNT = ##ROWCOUNT
SET #spRETURN = #spRETURN + 1
IF ( #spROWCOUNT <= 0
OR #spERROR <> 0
)
SET #spRETURN = 0 - #spRETURN
IF ( #spROWCOUNT <= 0
OR #spERROR <> 0
)
RETURN #spRETURN
SELECT #spROWCOUNT = -1 ,
#spERROR = -1
------------------ OLD SCHOOL ERROR TRAP END ------------------
In your try catch block, the last statement is probably doing something that sets the row count to 0. The "SELECT NULL" is setting the row count to 1, since it returns one row, so no error is detected.
You can fix this by changing the logic in the "old" code or by setting your row count variable in the try/catch code. I would recommend that you remove the SELECT NULL, since it would guarantee success and you may not want that behavior.

T-SQL Output Message During execution in SSMS

I have a simple query which loops and I want to see the PRINT messages during the execution. The query is something like this:
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
PRINT 'here'
END
The PRINT 'here' does not output until I stop the process. However, I want to see it while it's running. Is this possible?
You can use RAISERROR with serverity 0 and the NOWAIT option
WHILE 1 = 1
BEGIN
WAITFOR DELAY '000:00:10'
RAISERROR ('here', 0, 1) WITH NOWAIT
END
I believe that the prints get buffered, releasing "chunks" as the buffer fills up.
try using raiserror:
How do I flush the PRINT buffer in TSQL?
Try this..
DECLARE #i INT = 1
WHILE ( #i <= 10)
BEGIN
--- do something
SELECT 'Completed ' + CAST(#i AS VARCHAR(50)) + ' : ' + CAST(GETDATE() AS VARCHAR(50));
SET #i = #i + 1
END
current suggestions don't work for SSMS 18 and above.
Print then raiserror(N'', 0, 1) seems to get around this.