SQL Server select variable where no results - sql

Can I set variables if the query returns no results?
DECLARE #Output AS VARCHAR(MAX);
SELECT #Output = 'Old';
SELECT #Output = 'New' WHERE 0 = 1;
PRINT #Output;
Output value is: Old
Expected value is: NULL

DECLARE #Output AS VARCHAR(MAX);
SELECT #Output = 'Old';
SELECT #Output = 'New' WHERE 0 = 1;
PRINT #Output;
You get 'Old' cause the variable already has this value, and it will not update the value since in the WHERE clause you use the condition 0=1, which will return FALSE and the value in the variable won't change.
WHERE 0 = 1 It will be False
WHERE 0 <> 1 It will be True
It's just similar to IF 0=1 THEN UpdateMyVar
So in your case the value will always 'Old', it won't return 'New' or NULL either.
I don't know what are you trying to do really, but if you want to return NULL then
DECLARE #Output AS VARCHAR(MAX);
SELECT #Output = 'Old';
SELECT #Output = NULL WHERE 0 <> 1; --If 0<> 1 then update my var and set NULL else leave it as it is
PRINT #Output;

Try this:
DECLARE #Output AS VARCHAR(MAX);
SELECT #Output = 'Old';
SELECT #Output = CASE 0 WHEN 1 THEN 'New' ELSE NULL END
SELECT #Output;

Sami provides a good explanation of what is going on.
If you want to be sure that a value is assigned, then you need to be sure that the query returns one row for the assignment. One way to do this is to use aggregations:
DECLARE #Output AS VARCHAR(MAX);
SELECT #Output = 'Old';
SELECT #Output = MAX('New') WHERE 0 = 1;
SELECT #Output;

This is simply how assigning variables in SELECT is implemented in SQL Server. As #SMor said in the comments, use SET instead of SELECT.
DECLARE #Output AS VARCHAR(MAX);
SET #Output = 'Old';
SET #Output = (SELECT 'New' WHERE 0 = 1);
-- this would change the #Output value to NULL
SELECT #Output;
The only problem with SET is that it can assign only one variable, while in SELECT you can assign many variables at the same time.

Related

Comma Separated List from SQL Grouping

I'm trying to build comma separated list per group in sql,
As am using Parallel Data Warehouse i need to do this without using FOR XML or recursive function ( not supported ).
any other way to achieve this ?
Input:
ID Value
1 2
1 3
1 4
2 1
2 10
Output:
ID List
1 2,3,4
2 1,10
This will not perform well at all so I recommend you use some other solution (like a SQL Server linked server to PDW) if you need performance. But I believe this should work on PDW:
declare #ID int = (select min(ID) from tbl);
declare #Value int = -1;
declare #concat varchar(8000) = '';
create table #tmp (
ID int,
[concat] varchar(8000)
)
with (distribution=hash(ID), location=user_db);
while #ID is not null
begin
set #Value = (select min([Value]) from tbl where ID = #ID and [Value]>#Value);
if #Value is not null
set #concat = #concat + case when #concat = '' then '' else ',' end + cast(#Value as varchar(8000));
else
begin
insert #tmp (ID, [concat])
values (#ID, #concat);
set #ID = (select min(ID) from tbl where ID > #ID);
set #Value = -1;
set #concat = '';
end
end
select * from #tmp;
drop table #tmp;

SQL: how to check palindrome of a string without using reverse function?

I'm using SQL Server and I want to check whether the given string is a palindrome or not - but without using the reverse function.
There are multiple ways to achieve this. One of them is to check first and last character, slicing them if they're equal and continuing the process in a loop.
DECLARE #string NVARCHAR(100)
DECLARE #counter INT
SET #string = 'Your string'
SET #counter = LEN(#string)/2
WHILE (#counter > 0)
BEGIN
IF LEFT(#string,1) = RIGHT(#string,1)
BEGIN
SET #string = SUBSTRING(#string,2,len(#string)-2)
SET #counter = #counter - 1
END
ELSE
BEGIN
PRINT ('Given string is not a Palindrome')
BREAK
END
END
IF(#counter = 0)
PRINT ('Given string is a Palindrome')
A select without loops
DECLARE #Test VARCHAR(100)
SELECT #Test = 'qwerewq'
SELECT CASE WHEN LEFT(#Test, LEN(#Test)/2) =
(
SELECT '' + SUBSTRING(RIGHT(#Test, LEN(#Test)/2), number, 1)
FROM master.dbo.spt_values
WHERE type='P' AND number BETWEEN 1 AND LEN(#Test)/2
ORDER BY number DESC
FOR XML PATH('')
)
THEN 1
ELSE 0
END
Here's an example using LEFT and RIGHT. I use the #count variable to change position, then grab the left-most and right-most char:
DECLARE #mystring varchar(100) = 'redivider'
DECLARE #count int = 1
WHILE (#count < LEN(#mystring) / 2) AND #count <> 0
BEGIN
IF (RIGHT(LEFT(#mystring, #count), 1) <> LEFT(RIGHT(#mystring, #count), 1))
SET #count = 0
ELSE SET #count += 1
END
SELECT CASE WHEN #count = 0
THEN 'Not a Palindrome'
ELSE 'Palindrome'
END [Result]

SQL Query to remove common string

#strA and #strB are two variables
#strA = "055367911126753316"
#strB = "00055367"
how to find the common part "055367" and remove it from string A, using SQL server query without looping?
the result should be "911126753316"
be noted that always string A begin by the end part of string B
You can use replace in sql server as below:
declare #strA varchar(50) = '055367911126753316'
declare #strB varchar(50) = '00055367'
select replace(#strA,right(#strB,len(#strB)-2),'')
If it is in different columns in a table you can use as below:
create table #yourcolumns ( cola varchar(50), colb varchar(50))
insert into #yourcolumns (cola, colb) values
('055367911126753316', '00055367')
select replace(cola,right(colb,len(colb)-2),'') from #yourcolumns
I think we need to go for substring in your case as you are looking for startswith
select SUBSTRING(cola,CHARINDEX(LEFT(REVERSE(colb),1),cola)+1,len(cola)) from #yourcolumns
Try This, works dynamically.
declare #StrA Nvarchar(250)='055367911126753316',#StrB Nvarchar(250)='0055367'
select right(#StrA,len(#strA)-PATINDEX('%[^'+#StrB+']%',#strA)+1)
It YES with looping, But it work....
create function MyFn (#A nvarchar(max), #B nvarchar(max))
returns nvarchar(max)
as
begin
declare #I int, #L int, #SUB nvarchar(max)
select #I = 1, #L = len(#B)
while #I<#L begin
set #SUB = substring(#B,#I,#L-#I+1)
if charindex(#SUB,#A,1) > 0 begin
set #A = replace(#A, #SUB, '')
break
end
set #I = #I + 1
end
return #A
end
If each string A starts with 000 and each string b just contains one 0 this should retrieve the correct result
WITH CTE AS (SELECT [StringA], [StringB],REPLACE([StringB], '000', '0') [tbd]
FROM YourTable)
SELECT REPLACE(YourTable.[StringA], CTE.[tbd], ''), YourTable.[StringA]
FROM YourTable
JOIN CTE ON YourTable.[StringA]= CTE.[StringA]
DECLARE #strA varchar(50) = '055367911126753316'
DECLARE #strB varchar(50) = '00055367'
SET #strA=(SELECT REVERSE(SUBSTRING(#strA, PATINDEX('%[^0 ]%', #strA + ' '), LEN(#strA))))
SET #strB=(SELECT REVERSE(SUBSTRING(#strB, PATINDEX('%[^0 ]%', #strB + ' '), LEN(#strB))))
SELECT #strA String ,#strB StringtoSearch,REVERSE(SUBSTRING(#strA,0,CHARINDEX(RIGHT(#strA,LEN(#strB)),#strA)))ExpectedOutput
Output
ExpectedOutput
---------------
911126753316

Select and Set not working together in TSQL FUNCTION

I am using a function in SQL SERVER and setting a user variable using select and after that set . But seems set is not working .
--#id is input
Declare #result varchar(MAX)
SELECT #result = INFO FROM USER_INFO WHERE ID= +''+'DOMAIN\'+#id+''
IF #result IS NULL
SET #result = 'DOMAIN\'+#id+''
return (#result)
If user is not found I want to select id not the null values. Buts seems it coming null always
Set is not working in conditional statement.
What I am doing wrong?
Below is the update:
yes Slippery, I checked its coming null. If I set
SET #result ='MY ID'
it works but #result = 'DOMAIN\'+#id did not work
The whole function
FUNCTION [dbo].[USER_INFO]
(
-- Add the parameters for the function here
#id varchar(300)
)
RETURNS varchar(MAX)
AS
BEGIN
Declare #result varchar(MAX)
SELECT #result = INFO FROM USER_INFO WHERE ID= +''+'DOMAIN\'+#id+''
IF #result IS NULL
SET #result = 'DOMAIN\'+#id+''
return (#result)
END
Just in case that really is the entire function, you'll need that first line to be "CREATE FUNCTION" (or "ALTER FUNCTION" if it already exists), instead of just "FUNCTION"...
This will eliminate NULL's from being returned by your function:
DECLARE #result VARCHAR(MAX)
-- Eliminate NULL being passed in so string concatenation doesn't return NULL
IF #id IS NULL
SET #id = ''
-- Set the output value...if nothing exists, set it to 'x'
SET #result = (SELECT TOP 1 ISNULL(INFO,'x') FROM USER_INFO WHERE ID = 'DOMAIN\' + #id);
-- Now, neither #result OR #id will be NULL so the following should always return something other than NULL
IF #result = 'x'
SET #result = 'DOMAIN\' + #id
RETURN (#result)
Based on the other comments, try this:
Declare #result varchar(MAX)
SELECT #result = INFO FROM USER_INFO WHERE ID= 'DOMAIN\'+#id
IF #result IS NULL
SET #result = 'DOMAIN\'+ ISNULL(#id, '')
return (#result)
I don't think you need all that handing with the quotes and pluses
You should try like this. No need of those extra '' single quotes at end
Declare #result varchar(MAX)
SELECT #result = INFO FROM USER_INFO WHERE ID= 'DOMAIN\' + #id
IF #result IS NULL
SET #result = 'DOMAIN\' + #id
return (#result)
Few points to mention: your function name and the table name both are same user_info. Try naming them differently like
FUNCTION [dbo].[Get_USER_INFO]
(
-- Add the parameters for the function here
#id varchar(300)
)
SELECT #result = INFO FROM USER_INFO
Also, you should call your function like
select dbo.Get_USER_INFO('my-user_id')
The difference between select and set is that if set didn't found any value then it will return null but if select didn't found any value then it will show the previous value of the variable, the same case is happening for you when the #result value is null select don't assign any value and return the same previous value instead of assigning null and that is the reason the if statement is false and its not moving to the Set statement.
koppinjo, if the #result variable never set to anything then it should hit the block, but i guess the first time the #result variable value is not null so it's not hitting the block.
please view this for post more clarification.
http://www.mssqltips.com/sqlservertip/1888/when-to-use-set-vs-select-when-assigning-values-to-variables-in-sql-server/

T-SQL While Loop and concatenation

I have a SQL query that is supposed to pull out a record and concat each to a string, then output that string. The important part of the query is below.
DECLARE #counter int;
SET #counter = 1;
DECLARE #tempID varchar(50);
SET #tempID = '';
DECLARE #tempCat varchar(255);
SET #tempCat = '';
DECLARE #tempCatString varchar(5000);
SET #tempCatString = '';
WHILE #counter <= #tempCount
BEGIN
SET #tempID = (
SELECT [Val]
FROM #vals
WHERE [ID] = #counter);
SET #tempCat = (SELECT [Description] FROM [Categories] WHERE [ID] = #tempID);
print #tempCat;
SET #tempCatString = #tempCatString + '<br/>' + #tempCat;
SET #counter = #counter + 1;
END
When the script runs, #tempCatString outputs as null while #tempCat always outputs correctly. Is there some reason that concatenation won't work inside a While loop? That seems wrong, since incrementing #counter works perfectly. So is there something else I'm missing?
Looks like it should work but for somereason it seems to think #tempCatString is null which is why you are always getting a null value as nullconcatenated to anything else is still null. Suggest you try with COALESCE() on each of the variables to set them to " " if they are null.
this would be more efficient....
select #tempCatString = #tempCatString + Coalesce(Description,'') + '<br/>' from Categories...
select #fn
also look at concat_null_yields_null as an option to fix your concatenation issue, although I would avoid that route
I agree with keithwarren, but I would always be sure to add an ORDER BY clause to the query. You can then be sure as to exactly what order the values are being concatenated in.
Also, the COALESCE to replace the NULL value with '' will effectively yield blank rows. I don't know if you want them or not, but if not just filter in the WHERE clause instead...
Finally, you appear to have a temp table including the IDs you're interested in. This table can just be included in a JOIN to filter the source table...
DELCARE #output VARCHAR(8000)
SET #output = ''
SELECT
#output = #output + [Categories].Description + '<br/>'
FROM
Categories
INNER JOIN
#vals
ON #vals.val = [Categories].ID
WHERE
[Categories].Description IS NOT NULL
ORDER BY
[Categories].Description