Change columnname with variable in WHILE loop SQL - sql-server

Say i have columns PlanSalesMt1, PlanSalesMt2 and so on for the whole year until Mt12 in a table.
Before i created a view where i unioned all the months togheter but that query is pretty slow. Now i want to try the query with a Loop.
My Problem is i can't use the variable in my column names because they get invalid. Is that a way to solve this?
What i mean is i want to loop my question 12 times and change the name of the columns also after what month it is. But i cant make a #i variable and say select PlanSalesMt#1 or PlanSalesMt+#1 or PlanSalesMt+CAST(#1 as varchar) becuase it says invalid column Name.

Here is an example of dynamic SQL
DECLARE #ColumnName1 VarChar(20)
DECLARE #ColumnName2 VarChar(20)
DECLARE #sql Varchar(1000)
DECLARE #MyWhere VarChar(20)
SET #ColumnName1 = 'PlanSalesMt1'
SET #ColumnName2 = 'PlanSalesMt2'
SET #MyWhere = 'Books'
SET #sql = 'SELECT ' + #ColumnName1 + ', ' + #ColumnName2 + ' FROM TABLE WHERE ' + #ColumnName1 + ' = ''' + #MyWhere + ''''
EXEC(#sql)
If you change EXEC(#sql) to SELECT #sql copy into SSMS and run it you will see the query this produces.

Related

Invalid Column name on parameter input

Really wrecking my head here and as with many sql mess up I know it is probably something silly and stupid but I just cant seem to get it to work.
I have a stored procedure which is this..
ALTER PROCEDURE [dbo].[RETURN_DATA](#TABLE_param VARCHAR(7),#COUNTRY_param VARCHAR(2),#FILEDATE_param int,#TTKT_param VARCHAR(6))
AS
BEGIN
SET NOCOUNT ON;
SELECT #SQL = 'Select * from ' + #TABLE_param + ' WHERE COUNTRY = ' + #COUNTRY_param + ' AND MONTH(Fil_Dte) = ' + cast(#FILEDATE_param as varchar(20)) + ' AND TRNN = '+ #TKTT_param
EXECUTE(#SQL)
END
I'm using it in a vb.net windows form app so applying the parameters there. But trying to run it in SSMS with this
exec RETURN_DATA #COUNTRY_param='GB',#FILEDATE_param=4,#TABLE_param='table30',#TTKT_param='000000'
Returns the error
Invalid column name 'GB'. which i find strange as I never called for a column called GB but called for rows with GB in the column COUNTRY in my where clause?
I know this hopefully is a simple fix so any help would be greatly appreciated and also even if you think theres a better way to go about writing the SP!
Thanks in advance guys.
I'd recommend parameterising the SQL which will guard against SQL injection and you don't have to worry about escaping quotes as below
ALTER PROCEDURE [dbo].[RETURN_DATA](#TABLE_param VARCHAR(7),#COUNTRY_param VARCHAR(2),#FILEDATE_param int,#TTKT_param VARCHAR(6))
AS
BEGIN
SET NOCOUNT ON;
SELECT #SQL = 'Select * from ' + #TABLE_param + ' WHERE COUNTRY = ''' + #COUNTRY_param + ''' AND MONTH(Fil_Dte) = ' + cast(#FILEDATE_param as varchar(20)) + ' AND TRNN = '''+ #TKTT_param +''''
EXECUTE(#SQL)
END
Use sp_executesql to run dynamic sql
DECLARE #SQL NVARCHAR (4000);
SET #SQL = '
Select *
from ' + QUOTENAME(#TABLE_param) + '
WHERE COUNTRY = #COUNTRY_param
AND MONTH(Fil_Dte) = #FILEDATE_param
AND TRNN = #TTKT_param
';
EXEC sp_executesql #SQL,
N'#COUNTRY_param VARCHAR(2), #FILEDATE_param int, #TTKT_param VARCHAR(6)',
#COUNTRY_param, #FILEDATE_param, #TTKT_param;
sp_executesql

Dynamically insert data into a temp table with like as variable

I am trying to dynamically insert data into a temp table passing like data as a variable:
DECLARE #data NVARCHAR(MAX)
SET #data = 'INSERT INTO #coco ' + '([' + #val + '])' + ' SELECT [USER_ID] FROM [dbo].[Sheet1$] WHERE [Standard_Name] LIKE ' + #val
EXEC sp_executesql #data
#val is a column name selected from table Sheet1$ and few column name has space between them. While executing, I am getting error, like for column name "Acrobat Reader":
Incorrect syntax near 'Acrobat'.
Also if I am adding data using hardcoded one by one in a column its adding data to one column while other column its adding NULL.
Any suggestion how I can overcome this?
Parametrise your SQL, and this problem "goes away":
DECLARE #data;
SET #data = N'INSERT INTO #Coco (' QUOTENAME(#val) + N')' + NCHAR(10) +
N'SELECT [USER_ID]' + NCHAR(10) +
N'FROM dbo.[Sheet1$]' + NCHAR(10) +
N'WHERE [Standard_Name] = #val;'; --As this doesn't contain a %, there's no need for LIKE
EXEC sp_executesql #data,
N'#val = sysname', --guessed datatype
#val = #val;
Note the comments I made in the SQL though.
Afraid, I've no idea what your second statement means. You'll need to explain further.

SQL-Server Dynamic SQL failing

I have a stored procedure that dynamically generates a table to hold staging data for imports. This routine was running fine until Wednesday. I have tracked this down to one particular area. Code that's causing an issue is:
DECLARE #strSQL NVARCHAR(MAX) = N'';
SELECT #strSQL = #strSQL + N',[' + CustomerField + N'] NVARCHAR(MAX)' + CHAR(10)
FROM dbo.WebServices
WHERE CallType = 'customer'
AND IsPrimaryTable = 1
AND Source = 'clientName'
ORDER BY TagOrder;
SET #strSQL = STUFF(#strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(')+ N')';
PRINT #strSQL
NB. Table its pulling from holds a list of columns and the data hasn't changed either. There are about 34 rows of data with no special characters, and it isn't exposed to the clients.
This gives me an output of:
CREATE TABLE TableName
([CUSACNR2] NVARCHAR(MAX)
)
Running this on exactly the same data, even in the same window on SSMS, with an additional TOP filter gives me the results I was expecting i.e.
DECLARE #strSQL NVARCHAR(MAX) = N'';
SELECT TOP (99999) #strSQL = #strSQL + N',[' + CustomerField + N'] NVARCHAR(MAX)' + CHAR(10)
FROM dbo.WebServices
WHERE CallType = 'customer'
AND IsPrimaryTable = 1
AND Source = 'clientName'
ORDER BY TagOrder;
SET #strSQL = STUFF(#strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(')+ N')';
PRINT #strSQL
Generates the dynamic SQL:
CREATE TABLE TableName
([TAG] NVARCHAR(MAX)
,[CUSACNR] NVARCHAR(MAX)
.
.
.
,[SHIPPING_POSTAL_CODE] NVARCHAR(MAX)
,[CUSACNR2] NVARCHAR(MAX)
)
Specific column names removed for security
While I have tracked this down in one specific stored proc, we use this technique for building dynamic SQL a lot and I am seeing errors popping up in multiple places. I'm assuming that something has changed on the server as this has started happening in multiple databases at one time.
Does anyone know of anything that may have caused this issue? Its a legacy system that has been running fine for a long time and re-coding every instance of this type of activity is not an option.
I have found the answer. Sort of. I now know what had changed, so I've been able to correct it, but it should not have made any difference.
There was an index on the table that was causing the issue. Before you say that shouldn't make any difference, and you're right it shouldn't, I've managed to reliably solve and reproduce the problem by dropping and recreating the index.
So this isn't a fragmentation issue, it's not a clustered index, and the execution plan doesn't search by this index anyway.
CREATE NONCLUSTERED INDEX [idx_ntindex] ON [dbo].[WebServices] ([Source], [CallType], [SecurityKey])
GO
DECLARE #strSQL NVARCHAR(MAX) = N'';
SELECT #strSQL = #strSQL + N',[' + ISNULL(CustomerField,'') + N'] NVARCHAR(MAX)' + CHAR(10)
FROM dbo.WebServices
WHERE CallType = 'customer'
AND IsPrimaryTable = 1
AND Source = 'clientName'
ORDER BY TagOrder;
SET #strSQL = STUFF(#strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(') + N')';
PRINT #strSQL;
GO
DROP INDEX idx_ntindex ON dbo.WebServices
DECLARE #strSQL NVARCHAR(MAX) = N'';
SELECT #strSQL = #strSQL + N',[' + ISNULL(CustomerField,'') + N'] NVARCHAR(MAX)' + CHAR(10)
FROM dbo.WebServices
WHERE CallType = 'customer'
AND IsPrimaryTable = 1
AND Source = 'clientName'
ORDER BY TagOrder;
SET #strSQL = STUFF(#strSQL, 1, 1, 'CREATE TABLE ' + 'TableName' + CHAR(10) + '(') + N')';
PRINT #strSQL;
Gives me the results
CREATE TABLE TableName
([CUSACNR2] NVARCHAR(MAX)
)
CREATE TABLE TableName
([TAG] NVARCHAR(MAX)
,[CUSACNR] NVARCHAR(MAX)
,[DDAYS] NVARCHAR(MAX)
.
.
.
,[SHIPPING_POSTAL_CODE] NVARCHAR(MAX)
,[CUSACNR2] NVARCHAR(MAX)
)
If anyone knows WHY this is the case then please let me know. I found it but it doesn't make any sense to me.
Thanks for the help all. +1's for all the support, each suggestion got me a little closer.

Querying a column that contains comma separated values

I'm trying to figure out why my where clause is returning all rows.
I'm querying a column that contains csv's using a variable that also contains csv's. I've built a stored function to split the variable on csv and return a table with one row that contains what I'd like to have on the right side of the LIKE operator.
Example:
The stored function:
ALTER Function [dbo].[storedFunction]
(#Fields VARCHAR(MAX),
#Field_Name VARCHAR(MAX) = '')
RETURN #Tbl_Fields Table (FIELD Varchar(max))
AS
BEGIN
DECLARE #FIELD varchar(max) = REPLACE(#Fields, ',', '%''' + ' AND ' +
#Field_Name + ' Like ' + '''%');
INSERT INTO #Tbl_Fields
SELECT '''%' + #FIELD + '%'''
RETURN
END
Using the stored function:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns '%variable1%' AND main_csv_field Like '%variable3%'
My simplified query:
BEGIN
DECLARE #variable varchar(max) = 'variable1, variable3';
END
SELECT main_csv_field
FROM table
WHERE (main_csv_field LIKE (SELECT field
FROM storedFunction(#variable, 'main_csv_field');
returns
variable1,variable2,variable3,variable4,...
variable2,variable4,...
variable1,variable3,...
My problem is this last query returns all of the rows in the table regardless of value matching. Were I to copy and paste the value returned from the stored function I would get the data that I need.
How/what is the difference here?
Thanks to #Obie and #AllanS.Hansen I knew where to start looking to fix this. Its pretty rough, but I wanted to post a solution before I got too far down the rabbit hole:
DECLARE variable1 varchar(max) = '' --around 9 passed from code
DECLARE #query nvarchar(max);
DECLARE #column_list varchar(max) = 'column1, column2, etc'
--one of each of the tests per variable passed from code
DECLARE #variable1_test nvarchar(max) = (SELECT CASE WHEN #variable = '' THEN '%' ELSE (SELECT * from dbo.stored_function(#variable, 'column_name')) END);
END;
SET #query = ' SELECT ' + #column_list + '
FROM table_name
WHERE variable LIKE ''' + #variable_test + ''' '
EXECUTE sp_executesql #query;
print(#query); --This is just to see the resulting query, which helped me a ton
Exciting! Now I have to test it.

sql select columns based on name type

I am working in Microsoft SQL and I have a table where the column names are like 'INT001', 'INT002' all the way to 'INT300' but the columns don't show up in the particular order as the names above.
I want to select only columns from 'INT001' to 'INT096' i.e. 97 columns from 300 columns and the columns occur in random order in the table.
I don't even have a clue where to begin.
Edit: I don't want to type the 97 column names when they already have a pattern I can use if possible.
There is no way to do this in a query... What you can do is dynamically generate the query;
You can generate this in a number of ways... something like so (using just numbers to build the column names);
DECLARE #QueryString as varchar(max);
SELECT #QueryString = 'SELECT ';
SELECT
#QueryString = COALESCE(#QueryString + '[INT' + TheNumber + '],', '')
FROM
(SELECT DISTINCT RIGHT('000'+CAST(number AS VARCHAR(3)),3) AS TheNumber FROM master..[spt_values] WHERE number BETWEEN 0 AND 96) numbers
SELECT #QueryString = left(#QueryString, len(#QueryString) - 1) + ' FROM [YourTableName]'
print #QueryString
Gives us
SELECT [INT000],[INT001],[INT002],[INT003],[INT004],[INT005],[INT006],[INT007],[INT008],[INT009],[INT010],[INT011],[INT012],[INT013],[INT014],[INT015],[INT016],[INT017],[INT018],[INT019],[INT020],[INT021],[INT022],[INT023],[INT024],[INT025],[INT026],[INT027],[INT028],[INT029],[INT030],[INT031],[INT032],[INT033],[INT034],[INT035],[INT036],[INT037],[INT038],[INT039],[INT040],[INT041],[INT042],[INT043],[INT044],[INT045],[INT046],[INT047],[INT048],[INT049],[INT050],[INT051],[INT052],[INT053],[INT054],[INT055],[INT056],[INT057],[INT058],[INT059],[INT060],[INT061],[INT062],[INT063],[INT064],[INT065],[INT066],[INT067],[INT068],[INT069],[INT070],[INT071],[INT072],[INT073],[INT074],[INT075],[INT076],[INT077],[INT078],[INT079],[INT080],[INT081],[INT082],[INT083],[INT084],[INT085],[INT086],[INT087],[INT088],[INT089],[INT090],[INT091],[INT092],[INT093],[INT094],[INT095],[INT096] FROM [YourTableName]
This would also be easier and better using sys.columns to list the column names but since I don't have your table here or time to mock it up I have gone with a simple numbers one.
You can create your query by dynamically creating the SQL.
DECLARE #MAX INT = 97;
DECLARE #NUM INT = 1;
DECLARE #COLUMN NVARCHAR(500);
DECLARE #SQL NVARCHAR (1000) = 'SELECT ';
WHILE #NUM <= #MAX
BEGIN
SET #COLUMN = RIGHT(REPLICATE(0, 3) + CAST(#NUM AS VARCHAR(3)), 3)
SET #NUM = #NUM + 1;
SET #SQL = #SQL + '[INT' + #COLUMN + '], '
END
SET #SQL = #SQL + 'FROM [TABLENAME]'
SELECT #SQL --This is just to see the query
Once you have the query you can execute it by copy and paste or you can use this:
EXEC sp_executesql #SQL

Resources