To creating a dynamic union query in sql server - sql

I am trying to loop through my counter to create a dynamic sql query which should finally look like
I am trying to use this approach to get the final query but doesnt
seems to work
declare #CurrentRow int
set #CurrentRow =0;
declare #RowsToProcess int
declare #FinalHistoricalQuery varchar(5000)
WHILE #CurrentRow<3
BEGIN
SET #FinalHistoricalQuery =' select 11'+convert(varchar(20),#CurrentRow) + ' union '
SET #CurrentRow=#CurrentRow+1
END
SET #FinalHistoricalQuery = left(#FinalHistoricalQuery,len(#FinalHistoricalQuery)-6)
exec (#FinalHistoricalQuery)
the final ouput that i am looking for is 110 111 112 but it comes as 112
Any suggestion would be helpfull

You missed to use the counter in dynamic query. Try something like this.
WHILE #CurrentRow<#RowsToProcess
BEGIN
SET #FinalHistoricalQuery +=' select id from table'+convert(varchar(20),#CurrentRow) + ' union '
SET #CurrentRow=#CurrentRow+1
END
SET #FinalHistoricalQuery = left(#FinalHistoricalQuery,len(#FinalHistoricalQuery)-6)
exec (#FinalHistoricalQuery)

Related

Related to string manipulation

I have a table of crop which contain a column with crop name For Example Fruit and Nuts, Vegetables and Melons. I have to use T-SQL and remove the 'and' insert the spaces with a underscore and a text crop.groups should be added in front. For example Fruit and Nuts will become crop.groups.fruit_nuts. I have to to do these for all the crops together in SQL. When we run the query a separate column with these transformation should be generated. Also I have to create a function doing all this to me.
My Function:
CREATE function dbo.translationkey_v10
(
#column_name nchar(15)
)
returns nvarchar(1000)
as
begin
DECLARE #numletters int;
DECLARE #counter int;
DECLARE #str nvarchar(6);
DECLARE #newcolumn_name nvarchar(50)
SET #numletters = LEN(#column_name);
SET #counter = 1;
SET #newcolumn_name = '';
WHILE #counter <= #numletters
BEGIN
-- a. read next character:
----------------------------------------------------------------
SET #str = LOWER(SUBSTRING(#column_name, #counter, 1));
-- b. search for and in the string 'and':
----------------------------------------------------------------
IF (#str LIKE '%and%')
BEGIN
SET #str = REPLACE(#str,' and','')
END
-- c. check for space:
----------------------------------------------------------------
IF UNICODE(#str) = 32
BEGIN
SET #str = '_';
END
SET #newcolumn_name = #newcolumn_name + #str;
SET #counter = #counter + 1;
END
RETURN CONCAT('crop.groups.',#newcolumn_name)
END
Sample data
Crop name : Beverages and spice crops
Translation output : crop.group.beverages_spice_crops
This would seem very simple using replace:
select cropname, Concat('crop.groups.', Replace(cropname, ' and ','_'))
from crop

Apply filter on sql query conditionally

Lets say I have a parameter #Name in a Stored Procedure. I want to filter by this parameter only if it is not empty / null. In any other case I want to ignore the filter.
I came up with the following two solutions. For the sake of example let us consider only the case that parameter is empty.
select *
from MyTable
where (len(rtrim(ltrim(#Name))) > 0 and Name = #Name) or (len(rtrim(ltrim(#Name))) = 0)
and the second one
#query = 'select * from MyTable'
if (len(rtrim(ltrim(#Name))) > 0)
#query = #query + ' Name = #Name '
Both of the approaches are working as expected.
Which do you think is the most clean (in terms of code) and easily maintainable
Are there any other (better) alternatives.
Note: This question may also suit in Code Review, please comment if you think so, in order to migrate there
It can be simplified like this
select *
from MyTable
where Name = #Name or #Name = '' or #Name is null
or as mentioned in comments, use NULLIF to check for empty string then replace it with NULL then validate it against IS NULL
where (Name = #Name or nullif(#Name, '') is null)
You don't need to check for length, by default, sql server is trailing-spaces-sensitive (The only exception to this rule is when the right side of the LIKE predicate's expression contains trailing spaces, then the pad is not removed).
Take the code below.
DECLARE #Name=' '
IF(#Name='') SELECT 1 ELSE SELECT 0
If you run the above code above you will get a result of 1. In your case, you can drop the LTRIM and RTRIM and simply test for equality against an empty string literal.
select *
from MyTable
where ((#Name='' OR #Name IS NULL)OR(Name = #Name))
OR
IF(#Name='') SET #Name=NULL
select *
from MyTable
where (#Name IS NULL OR Name = #Name)
if you are working with dynamic sql in stored procedure try something like this . It is better to use different variables for main select query and dynamic where query which can be extended easily . using this approach it will be easy to maintain when you proc becomes lengthy.
declare #finalquery varchar(max)
declare #mainSelectquery nvarchar(500);
declare #whereCondtions varchar (1000);
declare #DateParam datetime
set #mainSelectquery=''
set #whereCondtions =''
set #finalquery =''
set #DateParam=getdate()
set #mainSelectquery = 'select * from tblOrders where 1=1 '
set #whereCondtions = ' and Order_site =''TSN'''
set #whereCondtions = #whereCondtions + ' AND CAST(ORDER_APPROVED_DATE_LT AS DATE)=CAST(GETDATE() AS DATE)'
set #finalquery =( #mainSelectquery + #whereCondtions)
print #finalquery
---- You can further extend this by adding more where condition based on the parameter pass in stored proc
if (#OrderID !=0)
begin
set #whereCondtions = ' OrderID='+str ( #stateRefID )
end

SQL - select from variable

I am trying to find an alternative to setting the content of a variable as a big query in which i'm dynamically replacing values.
Is it possible to do something like this?
declare #serv nvarchar(max)
set #serv = '[linkedServName].[dataBaseName]'
select top 10 * from #serv.dbo.someTable
If yes, could you please show me the correct syntax?
Thank you for your time
If you want to parameterize the server and database you select from, then you have to use dynamic sql. Try this:
declare #serv nvarchar(max)
declare #qry nvarchar(max)
set #serv = '[linkedServName].[dataBaseName]'
set #qry = 'select top 10 * from ' + #serv + '.dbo.someTable'
exec(#qry)

Update multiple columns using variable as column with concatination inside while loop

I have a situation where i want to update multiple columns but i don't want to write so many UPDATE lines.
Is it possible to use a variable as column name ? , then that variable will change inside WHILE loop, consider the following sample below.
EX:
Table: Test
Column01
Column02
Column03
Column04
Column05
Column06
Column07
Column08
Column09
Column10
DECLARE #ctr INT = 01
WHILE #ctr <= 10
BEGIN
-->> Is it possible to perform concatenation here to manipulate column name ?
UPDATE Test SET (Column + #ctr) = SomeValueHere... -->> assume that #ctr = 01
END
SET #ctr = #ctr + 1
The query every loop will look something:
-->> The first loop will look something like
UPDATE Test SET Column01 = SomeValueHere...
-->> The second loop will look something like
UPDATE Test SET Column02 = SomeValueHere...
How can i achieve this ?
Thank in advance.
You can do this with dynamic SQL.
DECLARE #script NVARCHAR(max)
SET #script = 'UPDATE Test SET (Column' + #ctr + ') = ' [whatever]
EXECUTE (#script)

How to dynamically specify a column in stored procedure

I need to write a stored procedure which will update into a particular column, based on parameters. This will be called from a C# app.
The table to be updated is like this:
TableA: Id, Col1, Col2, Col3.
Something like this:
Create Procedure UpdateByCol
#col_num int,
#value string,
#id int
as
Begin
Update TableA Set *How do I specify the column here* = #value where Id = #id
End
Declare #SQL varchar(max)
Set #SQL = 'Update ' + #TableName + ' Set ' + #Col1 + ' = ' + #Col1Val....
Exec (#SQL)
This exposes you to SQL injection though...
There is a way to do this without dynamic sql. Create individual stored procs for each column that is eligible for updating. Then, in your master stored proc, call the applicable stored proc based on the paramter received.
If you really want to do this it can be done with dynamic sql. http://technet.microsoft.com/en-us/library/ms188001.aspx
It is not good practice to do this but if you really wanted to you'd have to use dynamic sql to create the string and execute it like so:
Create Procedure UpdateByCol
#col_num int,
#value string,
#id int
as
Begin
declare #str varchar(2000)
set #str = 'Update TableA Set Col' + convert(varchar,#col) + ' = ''' + #value + ''' where Id = ' + convert(varchar, #id )
exec ( #str )
End
This is a very bad thing to do because it creates a security hole.