SQL output from dynamic SQL - sql

I have an stupid question about output.
I have an stored procedure that inside is doing a dynamic SQL for checking if there are records in a table, this is the example:
SET #sqlLog =
'SELECT 1 FROM MyTable
WHERE TableName = ''' + #TableName + '''' + '
AND TheKey = ''' + convert(varchar(50), #LoadGuid) + ''''
EXEC(#sqlLog)
After that I'm using ##RowCount to validate if the result is 0 or not.
The problem is that is inside a WHILE and for each row is showing the result in the output window of SQL Management Studio and I don't really want this.
Any idea? Thank you!

Why do you even need dynamic SQL for this?, you could do something like the following:
IF EXISTS ( SELECT 1 FROM MyTable
WHERE TableName = #TableName
AND TheKey = convert(varchar(50), #LoadGuid))
BEGIN
-- Your logic here
END

If you just need to know the number of rows that result from the query, try changing the select list to only be 'SELECT COUNT(*) FROM MyTable ... '. This will give you the count as a single result.

I think you need to use the NOCOUNT option:
SET NOCOUNT ON
See http://msdn.microsoft.com/en-us/library/ms189837.aspx for details.
Good luck,
Dave Cherkassky

declare #count int
exec sp_executeSql
N'set #count = (select count(*) from MyTable where TableName = ''' + #tableName + '''
and TheKey = ''' + convert(varchar(50), #LoadGuid) + '''',
N'#count int output',
#count = #count output
if #count > 0
print 'rows exist'
else
print 'no rows'

There is no way to have it surpress the results of a straight select statement like that. You are literally telling it to return those results to the calling application, here SSMS, and it is doing so. SSMS is properly displaying those results. You have some options as to how you want to display them (results pane or as text, etc.), but I do not know of an option in SSMS to turn it off.
What you could do is use sp_executesql with an output paramater so that instead of requesting any results, you are simply having it put the rowcount in a parameter. That would look something like:
declare #theCount int
SET #sqlLog = 'SELECT #theCount = count(*)
FROM MyTable
WHERE TableName = ''' + #TableName + '''' +
' AND TheKey = ''' + convert(varchar(50), #LoadGuid) + ''''
EXEC sp_executesql #sqlLog, N'#theCount int OUTPUT', #theCount=#theCount OUTPUT
Then you check whether the value of #theCount is 0 instead of ##Rowcount.

Related

Is it possible to set a variable for a stored procedure as column type?

It seems like a simple enough event you just declare a variable you are passing to your stored procedure as column. I am needing to pass a column name to my stored procedure that will be used in my query. Is it possible to declare it so I can use it as a column name or is there some way I can convert say a string to column type?
where Line1AStatus = 1
I need to be able to pass to my stored procedure what that number is in Line Status. I have tried these methods so far. Thank you for your help.
where Line + #LineNum + AStatus = 1
where 'Line' + #LinNum + 'AStatus' = 1
not with standard SQL but you can with dynamic sql
DECLARE #SQL nvarchar(max)
SELECT #SQL = 'SELECT * FROM table where ''Line' + CAST(#LinNum AS NVARCHAR) + 'AStatus'' = 1'
exec sp_executeSQL #sql
Example of a while loop
DECLARE #SQL nvarchar(max), #LinNum int
SELECT #LinNum = 1
WHILE(#LinNum <= 5)
BEGIN
SELECT #SQL = 'SELECT * FROM table where ''Line' + CAST(#LinNum AS NVARCHAR) + 'AStatus'' = 1'
exec sp_executeSQL #sql
SELECT #LinNum = #LinNum + 1
END

SQL Filter Null Columns

I have a query like
select *
from tableName
where x='3'
This gives me back some number of results, but I don't want to see any columns where every row is Null. Is there an easy way to filter those out?
No there isn't.
What you are after is some syntax like
select <column list::filter(where all rows are NULL)>
However, it just doesn't make sense. Not in a general sense. It might look cool when used in SSMS or a one-off query tool, but for day-to-day usage by Joe Public in programs like ASP.Net, who'd want an unpredictable number of columns?
Now if you really wanted to do it, this can be achieved with dynamic SQL, but it would have to be coded ONCE-PER-TABLE that you want to query this way.
You can try some crazy stuff with dynamics SQL but I really wouldn’t recommend this.
This query checks if first two columns have all null values and then adds them to select statement. If you really want to go this way you can to the same for all columns in your table.
DECLARE #sql nvarchar(1000)
DECLARE #columnList nvarchar(1000)
SET #columnList = ''
DECLARE #tableRowCount int
DECLARE #columnRowCount int
SET #tableRowCount = (select COUNT(*) from tableName)
SET #columnRowCount = (select COUNT(*) from tableName where column1 is null)
IF #tableRowCount <> #columnRowCount
SET #columnList = #columnList + 'column1, '
SET #columnRowCount = (select COUNT(*) from tableName where column2 is null)
IF #tableRowCount <> #columnRowCount
SET #columnList = #columnList + 'column2, '
IF LEN(#columnList) > 0
SET #sql = 'SELECT ' + SUBSTRING(#columnList,1, LEN(#columnList) - 1) + ' FROM tableName'
ELSE
SET #sql = 'SELECT * FROM tableName'
EXEC(#sql)

Execute a Stored Procedure in a SELECT statement

For an instance I a select statement and it is returning 1000 rows. I need to execute a particular stored procedure for every row the the select statement is returning.
have you got any idea how can I do that?
Construct the EXECUTE statements in your select like this:
SELECT 'EXEC sp_whatever ' + parameter stuff
FROM your_table
Then run the results! Alternatively, paste your results into a spreadsheet package, and use string concatenation to construct the EXEC statements - just create a formula and paste it down the 1,000 rows. I personally prefer the first approach.
To clarify the "parameter stuff", take the example of a stored procedure that takes two int parameters that you want to take from columns you your_table. You'd then have something like this:
SELECT 'EXEC sp_whatever ' + CAST(field1 AS varchar) + ', ' + CAST(field2 AS varchar)
FROM your_table
Not the need to be careful with string fields here - you run the risk of inadvertently exposing yourself to your own SQL injection attack, as with any SQL string concatenation.
I am reading your "for an instance" as "this is a one-off task". If this is a task that needs automating, then one of the other answers may be the right approach.
You can do it like this:
declare #execstatementsbatch nvarchar(max)
select #execstatementsbatch = ''
SELECT #execstatementsbatch = #execstatementsbatch + 'EXEC UpdateQty ' + ItemCode + ', ' + QtyBO + '; '
FROM ITEMSPO
INNER JOIN .....
<some conditions>
exec(#execstatementsbatch)
Disclaimer: I'm not sure if I understand your question correctly.
Assuming you are on SQL Server 2005 upwards, you could create a table-valued user defined function and use the OUTER APPLY operator in your query.
Most RDBMS will let you select rows from stored procedure result sets. Just put your stored procedures in the FROM clause, as you would for common table expressions. For instance:
SELECT sp.ColumnInResultSet, t.BaseTableColumnName
FROM sp_whatever ( Args) sp INNER JOIN BaseTable t ON t.ID = sp.ID;
CREATE PROCEDURE dbo.usp_userwise_columns_value
(
#userid BIGINT
)
AS
BEGIN
DECLARE #maincmd NVARCHAR(max);
DECLARE #columnlist NVARCHAR(max);
DECLARE #columnname VARCHAR(150);
DECLARE #nickname VARCHAR(50);
SET #maincmd = '';
SET #columnname = '';
SET #columnlist = '';
SET #nickname = '';
DECLARE CUR_COLUMNLIST CURSOR FAST_FORWARD
FOR
SELECT columnname , nickname
FROM dbo.v_userwise_columns
WHERE userid = #userid
OPEN CUR_COLUMNLIST
IF ##ERROR <> 0
BEGIN
ROLLBACK
RETURN
END
FETCH NEXT FROM CUR_COLUMNLIST
INTO #columnname, #nickname
WHILE ##FETCH_STATUS = 0
BEGIN
SET #columnlist = #columnlist + #columnname + ','
FETCH NEXT FROM CUR_COLUMNLIST
INTO #columnname, #nickname
END
CLOSE CUR_COLUMNLIST
DEALLOCATE CUR_COLUMNLIST
IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'v_userwise_columns_value')
BEGIN
SET #maincmd = 'CREATE VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), #userid) + ') as userid , '
+ CHAR(39) + #nickname + CHAR(39) + ' as nickname, '
+ #columnlist + ' compcode FROM dbo.SJOTran '
END
ELSE
BEGIN
SET #maincmd = 'ALTER VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), #userid) + ') as userid , '
+ CHAR(39) + #nickname + CHAR(39) + ' as nickname, '
+ #columnlist + ' compcode FROM dbo.SJOTran '
END
--PRINT #maincmd
EXECUTE sp_executesql #maincmd
END
-----------------------------------------------
SELECT * FROM dbo.v_userwise_columns_value

SQL query to return all rows where one or more of the fields contains a certain value

Is it possible to run a select on a table to quickly find out if any (one or more) of the fields contain a certain value?
Or would you have to write out all of the column names in the where clause?
As others have said, you're likely going to have to write all the columns into your WHERE clause, either by hand or programatically. SQL does not include functionality to do it directly. A better question might be "why do you need to do this?". Needing to use this type of query is possibly a good indicator that your database isn't properly normalized. If you tell us your schema, we may be able to help with that problem too (if it's an actual problem).
Dig this... It will search on all the tables in the db, but you can mod it down to just one table.
/*This script will find any text value in the database*/
/*Output will be directed to the Messages window. Don't forget to look there!!!*/
SET NOCOUNT ON
DECLARE #valuetosearchfor varchar(128), #objectOwner varchar(64)
SET #valuetosearchfor = '%staff%' --should be formatted as a like search
SET #objectOwner = 'dbo'
DECLARE #potentialcolumns TABLE (id int IDENTITY, sql varchar(4000))
INSERT INTO #potentialcolumns (sql)
SELECT
('if exists (select 1 from [' +
[tabs].[table_schema] + '].[' +
[tabs].[table_name] +
'] (NOLOCK) where [' +
[cols].[column_name] +
'] like ''' + #valuetosearchfor + ''' ) print ''SELECT * FROM [' +
[tabs].[table_schema] + '].[' +
[tabs].[table_name] +
'] (NOLOCK) WHERE [' +
[cols].[column_name] +
'] LIKE ''''' + #valuetosearchfor + '''''' +
'''') as 'sql'
FROM information_schema.columns cols
INNER JOIN information_schema.tables tabs
ON cols.TABLE_CATALOG = tabs.TABLE_CATALOG
AND cols.TABLE_SCHEMA = tabs.TABLE_SCHEMA
AND cols.TABLE_NAME = tabs.TABLE_NAME
WHERE cols.data_type IN ('char', 'varchar', 'nvchar', 'nvarchar','text','ntext')
AND tabs.table_schema = #objectOwner
AND tabs.TABLE_TYPE = 'BASE TABLE'
ORDER BY tabs.table_catalog, tabs.table_name, cols.ordinal_position
DECLARE #count int
SET #count = (SELECT MAX(id) FROM #potentialcolumns)
PRINT 'Found ' + CAST(#count as varchar) + ' potential columns.'
PRINT 'Beginning scan...'
PRINT ''
PRINT 'These columns contain the values being searched for...'
PRINT ''
DECLARE #iterator int, #sql varchar(4000)
SET #iterator = 1
WHILE #iterator <= (SELECT Max(id) FROM #potentialcolumns)
BEGIN
SET #sql = (SELECT [sql] FROM #potentialcolumns where [id] = #iterator)
IF (#sql IS NOT NULL) and (RTRIM(LTRIM(#sql)) <> '')
BEGIN
--SELECT #sql --use when checking sql output
EXEC (#sql)
END
SET #iterator = #iterator + 1
END
PRINT ''
PRINT 'Scan completed'
I think you'd need to list all the columns in the where clause. I'm far from a SQL wizard though...maybe someone else knows a way.
you will have to write it out
Of course you have to write out all columns you want to use as a criteria.
If you add what programming language you are using and in what type of environment you working we can give you a clue or solution of how to do it dynamically.
I think your question really was how to do this dynamically depending of what the user of your program fill in in the "search"-form.. Im right?
If not, then.. Give us more information. ;)

Executing dynamic SQL in a SQLServer 2005 function

I will preface this question by saying, I do not think it is solvable. I also have a workaround, I can create a stored procedure with an OUTPUT to accomplish this, it is just easier to code the sections where I need this checksum using a function.
This code will not work because of the Exec SP_ExecuteSQL #SQL calls. Anyone know how to execute dynamic SQL in a function? (and once again, I do not think it is possible. If it is though, I'd love to know how to get around it!)
Create Function Get_Checksum
(
#DatabaseName varchar(100),
#TableName varchar(100)
)
RETURNS FLOAT
AS
BEGIN
Declare #SQL nvarchar(4000)
Declare #ColumnName varchar(100)
Declare #i int
Declare #Checksum float
Declare #intColumns table (idRecord int identity(1,1), ColumnName varchar(255))
Declare #CS table (MyCheckSum bigint)
Set #SQL =
'Insert Into #IntColumns(ColumnName)' + Char(13) +
'Select Column_Name' + Char(13) +
'From ' + #DatabaseName + '.Information_Schema.Columns (NOLOCK)' + Char(13) +
'Where Table_Name = ''' + #TableName + '''' + Char(13) +
' and Data_Type = ''int'''
-- print #SQL
exec sp_executeSql #SQL
Set #SQL =
'Insert Into #CS(MyChecksum)' + Char(13) +
'Select '
Set #i = 1
While Exists(
Select 1
From #IntColumns
Where IdRecord = #i)
begin
Select #ColumnName = ColumnName
From #IntColumns
Where IdRecord = #i
Set #SQL = #SQL + Char(13) +
CASE WHEN #i = 1 THEN
' Sum(Cast(IsNull(' + #ColumnName + ',0) as bigint))'
ELSE
' + Sum(Cast(IsNull(' + #ColumnName + ',0) as bigint))'
END
Set #i = #i + 1
end
Set #SQL = #SQL + Char(13) +
'From ' + #DatabaseName + '..' + #TableName + ' (NOLOCK)'
-- print #SQL
exec sp_executeSql #SQL
Set #Checksum = (Select Top 1 MyChecksum From #CS)
Return isnull(#Checksum,0)
END
GO
It "ordinarily" can't be done as SQL Server treats functions as deterministic, which means that for a given set of inputs, it should always return the same outputs. A stored procedure or dynamic sql can be non-deterministic because it can change external state, such as a table, which is relied on.
Given that in SQL server functions are always deterministic, it would be a bad idea from a future maintenance perspective to attempt to circumvent this as it could cause fairly major confusion for anyone who has to support the code in future.
Here is the solution
Solution 1:
Return the dynamic string from Function then
Declare #SQLStr varchar(max)
DECLARE #tmptable table (<columns>)
set #SQLStr=dbo.function(<parameters>)
insert into #tmptable
Exec (#SQLStr)
select * from #tmptable
Solution 2:
call nested functions by passing parameters.
You can get around this by calling an extended stored procedure, with all the attendant hassle and security problems.
http://decipherinfosys.wordpress.com/2008/07/16/udf-limitations-in-sql-server/
http://decipherinfosys.wordpress.com/2007/02/27/using-getdate-in-a-udf/
Because functions have to play nicely with the query optimiser there are quite a few restrictions on them. This link refers to an article that discusses the limitations of UDF's in depth.
Thank you all for the replies.
Ron: FYI, Using that will throw an error.
I agree that not doing what I originally intended is the best solution, I decided to go a different route. My two choices were to use sum(cast(BINARY_CHECKSUM(*) as float)) or an output parameter in a stored procedure. After unit testing speed of each, I decided to go with sum(cast(BINARY_CHECKSUM(*) as float)) to get a comparable checksum value for each table's data.