NULLIF check for empty string returns empty string with a column name, but NULL with the column value - tsql

I have a database column set to char(255) (yes, CHAR. Don't ask me why that's how the database was set up) that at present has an empty string with two spaces (i.e. " "). Using NULLIF(LTRIM(RTRIM(column_name)), '') does NOT work (the output is [two empty spaces]). However, using NULLIF(' ', '') works correctly and the output is NULL. In other words, the actual column value works correctly, while passing the name of the column returns an incorrect value.
Any ideas on this?

I believe the column must have more than just spaces. For example:
CREATE TABLE #x(id INT, y CHAR(255));
INSERT #X SELECT 1, ' '
UNION ALL SELECT 2, ' '
UNION ALL SELECT 3, ' ' + CHAR(9);
SELECT id, NULLIF(LTRIM(RTRIM(y)),'') FROM #x;
Results:
1 NULL
2 NULL
3
For a row where this fails, try this:
DECLARE #s CHAR(255);
SELECT #s = y FROM #x WHERE id = 3;
DECLARE #i INT;
SET #i = 1;
WHILE #i <= DATALENGTH(#s)
BEGIN
IF ASCII(SUBSTRING(#s, #i, 1)) <> 32
BEGIN
PRINT 'Position ' + RTRIM(#i) + ' = CHAR('
+ RTRIM(ASCII(SUBSTRING(#s, #i, 1))) + ')';
END
SET #i = #i + 1;
END
It should tell you what other characters are in there, and where.

Related

How to concat two vars in while loop

I'd like to construct a 'union all' query with a while loop.
I've already tried += concatenation but doesn't work.
DECLARE #cnt1 int , #concat nvarchar(max), #qry nvarchar(500);
SET #cnt1 = 1;
WHILE #cnt1 < 99
BEGIN
SET #qry = 'select name_' + CAST(#cnt1 AS CHAR) + ' , name2_' + CAST(#cnt1 AS CHAR) + ', m.state1 FROM table1 P left join table2 M on M.name = P.name_' + CAST(#cnt1 AS CHAR) + ' where p.nb > 1';
SET #cnt1 = #cnt1 + 1;
SET #concat += ' UNION ALL ' + #qry
END
EXEC sp_executesql #concat
#concat is still empty at the end of the loop...
Thank you vm
Since #concat isn't initialized, the default value is null. Concatenating a value with null results in null, so no progress is made in your loop. Initializing it to an empty string:
declare #Concat as NVarChar(max) = N'';
will fix the problem.
Tip: The default length of a Char, VarChar, NChar or NVarChar is one character most of the time. When it is the target type of a Cast or Convert then it is 30 characters. Best practice: Always specify a length.

T-SQL Syntax - word parser

I have a word list in a variable. The words are comma delimited. I am trying to save them to individual record in a database. I found another question which does this and works, but it saves every word. I tried to modify it so that I only save unique words, and count duplicate as I go. I think the logic below is correct, but my syntax is not working.
if #FoundWord = 0 SET #WordsUsed = #WordsUsed + '' + #Word + ''
** is not concatenating the next word onto the end of the #WordsUsed variable
if #FoundWord = 0 INSERT INTO mydata.dbo.words (ProjectNumber, WordCount, Word) VALUES( '5', '1', #Word )
** doesn't seem to be doing anything at all ... I'm getting no records written to the words table
The entire code follows:
declare #SplitOn nvarchar(5) = ','
BEGIN
DECLARE #split_on_len INT = LEN(#SplitOn)
DECLARE #start_at INT = 1
DECLARE #end_at INT
DECLARE #data_len INT
DECLARE #WordsUsed varchar(max)
DECLARE #FoundWord int
DECLARE #Word varchar(100)
Set #WordsUsed = '**'
WHILE 1=1
BEGIN
SET #end_at = CHARINDEX(#SplitOn,#txt1,#start_at)
SET #data_len = CASE #end_at WHEN 0 THEN LEN(#txt1) ELSE #end_at-#start_at END
set #Word = SUBSTRING(#txt1,#start_at,#data_len)
SET #FoundWord = CHARINDEX('*' & #Word & '*', #WordsUsed)
if #FoundWord = 0 SET #WordsUsed = #WordsUsed & '*' & #Word & '*'
if #FoundWord = 0 INSERT INTO mydata.dbo.words (ProjectNumber, WordCount, Word) VALUES( '5', '1', #Word )
if #FoundWord > 0 Update mydata.dbo.words set WordCount = WordCount + 1 where projectnumber = 5 and word = #word
IF #end_at = 0 BREAK
SET #start_at = #end_at + #split_on_len
END
RETURN
END;
Here's a function you can try. It splits an unlimited-sized string based on the delimiter of your choice. The output of the function is a table - so you can then select distinct from that to store your word list. You'd call it something like:
insert YourWordlistTable ( Word ) --> just making up table/column names here
select distinct Data
from dbo.StringSplit( #yourVar, ',' )
Here's the definition of the function:
create function dbo.StringSplit
(
#string nvarchar( max ),
#delimiter nvarchar( 255 )
)
returns #t table ( Id int, Data nvarchar( 4000 ) )
as begin
with Split( startPosition, endPosition )
as
(
select
cast( 0 as bigint ) as startPosition,
charindex( #delimiter, #string ) as endPosition
union all
select
endPosition + 1, charindex( #delimiter, #string, endPosition + 1 )
from
Split
where
endPosition > 0
)
insert #t
select
row_number() over ( order by ( select 1 ) ) as Id,
substring( #string, startPosition, coalesce( nullif( endPosition, 0 ), len( #string ) + 1 ) - startPosition ) collate Latin1_General_CS_AS as Data
from
Split
option( maxrecursion 0 );
return;
end
I originally posted, then deleted, then reposted this when I realized I'd given an inline function I use that never got called on strings longer than 100 words. I've since modified it to support indefinite recursion - although it can't be an inline function this way.
Inline functions are generally faster because SQL can incorporate the inline function's statement into the query plan of the statements that call the function. However, that does not appear to be an option available in an inline function.
why can't you use
select count(distinct value) from dbo.split(',',#txt1) where #txt1 is he string will give you distinct count of words
If you are looking for word wise count
select value,count(1) from dbo.split(',',#txt1) group by value
shoud do this

Getting upper into lower case

In my SELECT statement, I have:
,UserName
When this comes through in the query, it appears as: JOHN.SMITH
Is it possible to use CAST or CONVERT to change this to John Smith?
Any advice gratefully appreciated.
Thanks.
First replace the period with a space:
SELECT REPLACE(SELECT UserName FROM YourTable, '.', ' ')
Save this in a variable, or put this select directly to the function below.
Unfortunately, I don't have t-sql at my disposal right now, so I can't check the syntax to be 100% correct.
Then to set only first chars to uppercase. If you were using oracle, I would tell you to use initcap, but this doesn't exist in t-sql.
Taken from link: http://www.devx.com/tips/Tip/17608
create function initcap (#text varchar(4000))
returns varchar(4000)
as
begin
declare #counter int,
#length int,
#char char(1),
#textnew varchar(4000)
set #text = rtrim(#text)
set #text = lower(#text)
set #length = len(#text)
set #counter = 1
set #text = upper(left(#text, 1) ) + right(#text, #length - 1)
while #counter <> #length --+ 1
begin
select #char = substring(#text, #counter, 1)
IF #char = space(1) or #char = '_' or #char = ',' or #char = '.' or #char = '\'
or #char = '/' or #char = '(' or #char = ')'
begin
set #textnew = left(#text, #counter) + upper(substring(#text,
#counter+1, 1)) + right(#text, (#length - #counter) - 1)
set #text = #textnew
end
set #counter = #counter + 1
end
return #text
end
So use this function to convert the uppercase string. Hope this helps.
You could go about it like so:
DECLARE #UserName AS varchar(50) = 'JOHN.SMITH'
SELECT LEFT(UPPER(LEFT(#UserName, CHARINDEX('.', #UserName)-1)),1) + SUBSTRING(LOWER(LEFT(#UserName, CHARINDEX('.', #UserName)-1)),2,LEN(LEFT(#UserName, CHARINDEX('.', #UserName)-1))-1) + ' ' + LEFT(UPPER(RIGHT(#UserName, LEN(#UserName) - CHARINDEX('.', #UserName))),1) + SUBSTRING(LOWER(RIGHT(#UserName, LEN(#UserName) - CHARINDEX('.', #UserName))),2,LEN(RIGHT(#UserName, LEN(#UserName) - CHARINDEX('.', #UserName)))-1)
It gets everything before the . and then uppers the first letter whilst lowering the rest and then does the same for everything after the ..
However, it would be much better if you handled this in your code as when you come back to reading this query you may not know what it's doing.

Invalid length parameter passed to the SUBSTRING function

I have written the query and it is working:
declare #word as nvarchar (20)
set #word = 'victOR aALEXander'
select upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
I have created the function:
alter function letters ( #word as nvarchar(20))
returns varchar(20) as begin
return upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word))) end
Finally i have done:
select dbo.letters(users)
from dbo.tempdb
I have got:
Invalid length parameter passed to the SUBSTRING function
Why?
Try this function:
Create Function dbo.Proper(#Data VarChar(8000))
Returns VarChar(8000)
As
Begin
Declare #Position Int
Select #Data = Stuff(Lower(#Data), 1, 1, Upper(Left(#Data, 1))),
#Position = PatIndex('%[^a-zA-Z][a-z]%', #Data COLLATE Latin1_General_Bin)
While #Position > 0
Select #Data = Stuff(#Data, #Position, 2, Upper(SubString(#Data, #Position, 2))),
#Position = PatIndex('%[^a-zA-Z][a-z]%', #Data COLLATE Latin1_General_Bin)
Return #Data
End
This function works properly whether there are spaces, apostrophes, or anything else in your data. Unfortunately it won't convert macdonald to MacDonald or o'brien to O'Brien. However, it will work for any word(s) that only have 1 capital letter in it.
also try trimming in case you have spaces at the beginning and end:
alter function letters ( #word as nvarchar(20))
returns varchar(20) as
begin
set #word = ltrim(rtrim(#word))
return upper(left(#word, 1)) + lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' ' +
upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
end
Character count of #word parameter is less than substring count. Also, parameter could be null.
try if this query works. However if you have more than single ' ' then this query will fail.
declare #word as nvarchar (20)
set #word = 'alex' -- 'victOR aALEXander'
select
upper(left(#word, 1)) +
CASE WHEN charindex(' ', #word)>0 THEN lower(SUBSTRING(#word,2,charindex(' ', #word)-2)) + ' '
+ upper(left(substring(#word,charindex(' ', #word)+1,len(#word)-1),1))
+ lower(SUBSTRING(#word,charindex(' ', #word)+2, len(#word)))
ELSE lower(SUBSTRING(#word,2,len(#word)-1)) END

tsql breaking a comma seperated string and then looping

i have comma seperated string
a=1,2,3,4
now i want to break this string and then loop through it using 1,2,3 etc in the query in tsql in sql server 2008
set #sql = #sql + ' and (ClassicStation.int_WheatherTypeId = a[i]) AND (ClassicStation.int_MeasurementId IN (1,2)) or'
In your example it looks to me like you can just do this:
set #sql = #sql + 'and (ClassicStation.int_WheatherTypeId in ('+#a+'))
AND (ClassicStation.int_MeasurementId IN (1,2))'
Otherwise you can split the string with the split function that is located everywhere or
like this
declare #a varchar(max)
set #a ='1,2,3,4' + ','
;with csv (col, pos) as
(
select left(#a, charindex(',', #a) -1),charindex(',', #a)
union all
select substring(#a, pos +1, charindex(',', #a, pos +1) - pos-1),
charindex(',',#a, pos+1) from csv
where pos < len(#a)
)
select * from csv
maybe fn_split is an option check http://odetocode.com/code/365.aspx