Output variable from dynamic SQL - sql-server-2008

I have an issue wen I try to output a value from a dynamic T-SQL Query inside of a stored procedure.
I try to execute the following and simply output a 1 if something was found:
SET NOCOUNT ON
DECLARE #returnValue int
DECLARE #Statement nvarchar(400)
set #Statement = 'SELECT #result=''1'' FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''sourceTable''
AND COLUMN_NAME = #columnIN
AND TABLE_SCHEMA = ''dbo'''
exec sp_executesql #Statement,
N'#columnIN nvarchar(60),#result INT OUTPUT',
#columnIN = #column, #result=#returnValue OUTPUT
select #returnValue
This currently yields NULL. Does anyone have any idea what I'm missing?
Additional Information:
The column that I try to lookup is for example column1 . If I run the SQL query with ...AND CLOUMN_NAME = 'column1' ... I get a 1 back.
If I print the #column variable in the SP I get 'column1'.
#column is declared as an input variable with nvarchar(60) in the SP: PROCEDURE [dbo].[usp_checkColumn] (#column nvarchar(60), #result INT OUTPUT)
As per request the complete SP here:
Create PROCEDURE [dbo].[usp_checkColumn] (#column nvarchar(60), #result INT OUTPUT)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON
DECLARE #returnValue int
DECLARE #Statement nvarchar(400)
set #Statement = 'SELECT #result=''1'' FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = ''t_table''
AND COLUMN_NAME = #columnIN
AND TABLE_SCHEMA = ''dbo'''
exec sp_executesql #Statement, N'#columnIN nvarchar(60),#result INT OUTPUT', #columnIN = #column, #result=#returnValue OUTPUT
select #returnValue
return #returnValue
END
And here's how I call the SP:
DECLARE fcursor CURSOR
FOR
select FieldName
from t_fieldDefinition
OPEN fcursor
Fetch next from fcursor into #field;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #tmpField = '''' + #field + ''''
SET #field ='[' + #field + ']'
set #available = 0
exec usp_checkColumn #tmpField,#available OUTPUT
If I print the [#column] variable in the usp_checkColumn I do get the correct column inside of the ''. If I copy & paste the print of this variable and insert it into the query I get a 1 back, if I run the SP I get NULL(converted to 0 as NULL is not valid for the INT variable) back.
Here's the content of the t_fieldDefinition table:
FieldName ID
Source 5
column1 6
column2 7
Client 8
asd BSX 9
bsd 10
esd 11
esx 12
And here's the definition of the t_table table:
ID bigint Unchecked
Source varchar(250) Checked
column1 varchar(250) Checked
column2 nvarchar(100) Checked
Client varchar(10) Checked
asd varchar(250) Checked
[asd BSX] varchar(250) Checked
so that means that it should return 1 for all that are inside of the table definition and 0 for all others. Is it possible that the fields with a white space can be the issue? Although they work as well when you do it manually. It's not that I really have an option to change it but at least I would now the cause of the issue then.

I'm going to venture an answer on this.
I do not recommend using a cursor to go through each column just to test if the column exists in another table. If you insist on using a cursor, you could use a subquery to limit the results that you're cycling through to only the columns that don't exist in the other table, eliminating the need for the stored procedure that checks each individually (which by the way I think makes more sense as a user function):
DECLARE fcursor CURSOR
FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
where table_name = 't_table' and not column_name in
(
SELECT COLUMN_Name FROM INFORMATION_SCHEMA.COLUMNS
where table_name = 't_fieldDefinition'
)
If your goal really is to alter the table to add any missing columns, then this can be improved by eliminating the cursor and outputting your results using FOR XML:
declare #sql varchar(max)
set #sql =
(
SELECT cast('ALTER TABLE t_fieldDefinition ADD [' + COLUMN_NAME + '] INT;' as varchar(max)) FROM INFORMATION_SCHEMA.COLUMNS
where table_name = 't_table' and not column_name in
(
SELECT COLUMN_Name FROM INFORMATION_SCHEMA.COLUMNS
where table_name = 't_fieldDefinition'
) FOR XML PATH ('')
)
print #sql
exec (#sql)

Related

How to not show certain columns in MySQL? [duplicate]

when I do:
SELECT *
FROM SOMETABLE
I get all the columns from SOMETABLE, but I DON'T want the columns which are NULL (for all records). How do I do this?
Reason: this table has 20 columns, 10 of these are set but 10 of them are null for certain queries. And it is time consuming to type the columnnames....
Thanks,
Voodoo
SQL supports the * wildcard which means all columns. There is no wildcard for all columns except the ones you don't want.
Type out the column names. It can't be more work than asking questions on Stack Overflow. Also, copy & paste is your friend.
Another suggestion is to define a view that selects the columns you want, and then subsequently you can select * from the view any time you want.
It's possible to do, but kind of complicated. You can retrieve the list of columns in a table from INFORMATION_SCHEMA.COLUMNS. For each column, you can run a query to see if any non-null row exists. Finally, you can run a query based on the resulting column list.
Here's one way to do that, with a cursor:
declare #table_name varchar(256)
set #table_name = 'Airports'
declare #rc int
declare #query nvarchar(max)
declare #column_list varchar(256)
declare columns cursor local for select column_name
from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = #table_name
open columns
declare #column_name varchar(256)
fetch next from columns into #column_name
while ##FETCH_STATUS = 0
begin
set #query = 'select #rc = count(*) from ' + #table_name + ' where ' +
#column_name + ' is not null'
exec sp_executesql #query = #query, #params = N'#rc int output',
#rc = #rc output
if #rc > 0
set #column_list = case when #column_list is null then '' else
#column_list + ', ' end + #column_name
fetch next from columns into #column_name
end
close columns
deallocate columns
set #query = 'select ' + #column_list + ' from ' + #table_name
exec sp_executesql #query = #query
This runs on SQL Server. It might be close enough for Sybase. Hopefully, this demonstrates that typing out a column list isn't that bad :-)

SQL method for returning data from multiple tables based on column names

I am trying to do something a little weird and cannot figure out the right method for getting it done. Essentially I am trying to pull all tables/views and columns where the column name is like some string. In addition to that I would like to pull 1 row of data from that table/view and column combination. The second part is where I am lost. I know I can pull the necessary tables/views and columns with the below select statement.
SELECT COLUMN_NAME AS 'ColumnName'
,TABLE_NAME AS 'TableName'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%email%'
ORDER BY TableName,ColumnName;
So that I get something like the below
|ColumnName |TableName |
|emailAddress |all_emails |
....
But I want to get something like this:
|ColumnName |TableName |Example |
|emailAddress |all_emails |first.last#gmail.com|
....
Can anyone offer any insight?
I can't think of a simple way to do this within a query, but here's one option...
Put the list of the columns and tables into a temp table and run them through a loop, using dynamic SQL to select the max row for each.
I've added plenty of comments below to explain it.
DECLARE #SQL NVARCHAR(1000)
DECLARE #TABLE NVARCHAR(1000)
DECLARE #COLUMN NVARCHAR(1000)
DECLARE #SAMPLE NVARCHAR(1000)
DROP TABLE IF EXISTS ##TABLELIST
SELECT COLUMN_NAME AS 'ColumnName'
,TABLE_NAME AS 'TableName'
,ROW_NUMBER() OVER (ORDER BY COLUMN_NAME,TABLE_NAME)[RN]
INTO ##TABLELIST
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%email%';
ALTER TABLE ##TABLELIST
ADD [Sample] NVARCHAR(1000) -- Add a column for your sample row.
DECLARE #ROWCOUNTER INT = 1 -- Add a counter for the loop to use.
WHILE #ROWCOUNTER <= (SELECT MAX([RN]) FROM ##TABLELIST) -- Keep the loop running until the end of the list.
BEGIN
UPDATE ##TABLELIST
SET #TABLE = TableName WHERE [RN] = #ROWCOUNTER -- Get the table name into a variable.
UPDATE ##TABLELIST
SET #COLUMN = ColumnName WHERE [RN] = #ROWCOUNTER -- Get the column name into a variable.
SET #SQL = 'SELECT #SAMPLE = MAX([' + #COLUMN + ']) FROM [' + #TABLE + ']' -- Create SQL statement to pull max column from table specified in variables.
EXEC SP_EXECUTESQL #SQL, N'#SAMPLE NVARCHAR(1000) OUTPUT', #SAMPLE OUTPUT -- Execute SQL and put the output into the #SAMPLE variable.
UPDATE ##TABLELIST
SET [Sample] = CAST(#SAMPLE AS NVARCHAR(1000)) WHERE [RN] = #ROWCOUNTER -- Insert the SQL output into the sample column.
SET #ROWCOUNTER = #ROWCOUNTER+1 -- Add one to the row counter to move to the next column and table.
END
SELECT * FROM ##TABLELIST -- Select final output.

Cast in SQL Server query

I am having a problem with executing one SQL query, Below is my stored procedure
Query
ALTER PROCEDURE ProcName
(
#iID VARCHAR(50),
#AccountID INT
)
AS
SET NOCOUNT ON
DECLARE #Sql VARCHAR(MAX)
SET #Sql = 'DELETE FROM ReferringPhysician WHERE iID IN(' + #iID + ') AND AccountID = '+ #AccountID + ''
EXEC (#Sql)
I am trying to execute this query but it gives me error because i am using exec(), Here in my where condition i am dealing with the string, and in another condition i am dealing with the int, so in second condition i am getting casting error! how can i get through this?
Any help is greatly Appreciated!
Thanks
Your query is susceptible to SQL injection.
One way to avoid the data type problem you are having is to pass proper data types where you can and not use EXEC() (more details here):
DECLARE #sql NVARCHAR(MAX) = N'DELETE dbo.referringPhysician
WHERE iID IN (' + #iID + ') AND AccountID = #AccountID;';
EXEC sp_executesql #sql, N'#AccountID INT', #AccountID;
You can completely protect this from SQL injection by using table-valued parameters and passing in a DataTable or other collection with proper types instead of a comma-delimited string. e.g.:
CREATE TYPE dbo.iIDs TABLE(iID INT PRIMARY KEY);
Now your stored procedure can avoid dynamic SQL altogether:
ALTER PROCEDURE dbo.ProcName -- always use schema prefix!
#iIDs dbo.iIDs READONLY,
#AccountID INT
AS
BEGIN
SET NOCOUNT ON;
DELETE r
FROM dbo.ReferringPhysician AS r
INNER JOIN #iIDs AS i
ON r.iID = i.iID
WHERE r.AccountID = #AccountID;
END
GO
Try this:
ALTER PROCEDURE ProcName
(
#iID VARCHAR(50),
#AccountID INT
)
AS
SET NOCOUNT ON
DECLARE #Sql VARCHAR(MAX)
SET #Sql = 'DELETE FROM ReferringPhysician WHERE iID IN(' + CAST(#iID AS VARCHAR) + ') AND AccountID = '+ CAST(#AccountID AS VARCHAR) + ''
EXEC (#Sql)

Dynamic sql insert into returns 'invalid column name'

I'm trying my first dynamic sql stored procedure. I need to append the exact same records into multiple tables with the same column names. What I have compiles, but when it runs I get 'invalid column name 'TradeDate. The driver sproc is first below, then the sproc containing the dynamic statement. If anyone could help, that'd be great..
ALTER PROCEDURE dbo.StoredProcedure2
AS
DECLARE #tableName varchar(120)
SET #tableName = 'tblDailyATR'
EXEC sprocAddDatesAndSymbolsToAggregatedStudy #tableName
RETURN
ALTER PROCEDURE dbo.sprocAddDatesAndSymbolsToAggregatedStudy
#table varchar(120)
AS
DECLARE #tableName varchar(120)
SET #tableName = #table
EXEC(
'INSERT INTO ' + #tableName + '(Symbol, TradeDate)
SELECT Symbol, TradingDate
FROM (SELECT tblSymbolsMain.Symbol, tblTradingDays.TradingDate
FROM tblSymbolsMain CROSS JOIN tblTradingDays
WHERE (tblTradingDays.TradingDate <= dbo.NextAvailableDataDownloadDate())) AS T1
WHERE (NOT EXISTS (SELECT TradeDate, Symbol
FROM' + #tableName +
' WHERE (TradeDate = T1.TradingDate) AND (Symbol = T1.Symbol)))')
RETURN
You're missing a space after the "FROM" in this line:
FROM' + #tableName +
Should be
FROM ' + #tableName +
Otherwise it's going to try running SELECT FROMTABLE.

Something equivalent to "SELECT * FROM (SELECT table_name FROM...)"?

This query runs, but it produces the name of a table as a result, rather than actually selecting from that table.
SELECT T.*
FROM (SELECT tablename
FROM ListOfTables
WHERE id = 0) AS T
where ListOfTables contains id=0, tablename='some_table', I want to return the same result set as if I had written this directly:
SELECT * FROM some_table
Is there a native way to do this in MySQL 5, or do I have to do in in the application?
To do this in MySQL, you need to create a prepared statement which you can only create from a user variable:
SELECT #tn := tablename FROM ListOfTables WHERE id = 0;
SET #qs = CONCAT('SELECT * FROM ', #tn);
PREPARE ps FROM #qs;
EXECUTE ps;
You need to use dynamic SQL to get this result (the below code assumes SQL Server, I can't speak for other RDBMS').
declare #tableName varchar(100)
declare #query varchar(500)
select #tableName = tablename
from ListOfTables
where id = 0
select #query = 'select * from ' + #tableName
exec (#query)
Almost the same as #Shark's answer, except you also quote the name of the table to avoid syntax errors.
-- Using variables just for better readability.
DECLARE #Name NVARCHAR(4000)
DECLARE #Query NVARCHAR(4000)
-- Get the relevant data
SET #Name = QUOTENAME(SELECT tablename FROM ListOfTables WHERE id=0)
-- Build query
SET #Query = 'SELECT * FROM ' + #Schema + '.' + #Name + ''
-- execute it.
EXEC(#Query)