2

The following stored procedure dynamically determines the columns in the specified table and returns all columns that are not null, however the stored proc is returning null despite results coming back when testing the dynamic query on its own, am I handling the dynamic query return results correctly?

CREATE PROCEDURE [dbo].[spGetTables] 
(
    @TableName    varchar(255)
,@ParamOut    varchar(2000) OUTPUT
)
AS

declare @CommaString varchar(max)
set @CommaString = ''

Declare @col varchar(255), @cmd nvarchar(max)
declare @colName varchar(2000)
SET @colName = ''

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = @TableName 

OPEN getinfo

FETCH NEXT FROM getinfo into @col

WHILE @@FETCH_STATUS = 0
BEGIN

    SELECT @cmd = 'IF NOT EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NULL or len([' + @col + ']) < 1) BEGIN select ''' + @col + ',''  END'

    exec sp_executesql @cmd, N'@Result varchar(max) out', @ParamOut out

    set @ParamOut = @ParamOut + @CommaString

    FETCH NEXT FROM getinfo into @col
END

PRINT 'Result: '+@ParamOut

CLOSE getinfo
DEALLOCATE getinfo
RETURN 0

4 Answers 4

3

Change the procedure to this one and try again:

CREATE PROCEDURE [dbo].[spGetTables] 
(
    @TableName    varchar(255)
,@ParamOut    varchar(2000) OUTPUT
)
AS

declare @CommaString varchar(max)
set @CommaString = ''

Declare @col varchar(255), @cmd nvarchar(max)
declare @colName varchar(2000)
SET @colName = ''

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = @TableName 

OPEN getinfo

FETCH NEXT FROM getinfo into @col

DECLARE @TempParamOut varchar(2000) = '';

WHILE @@FETCH_STATUS = 0
BEGIN

    SELECT @cmd = ' IF NOT EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NULL or len([' + @col + ']) < 1) BEGIN select @Result= ''' + @col + ',''  END'

    exec sp_executesql @cmd, N'@Result varchar(max) out', @TempParamOut out

    set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString;
    set @TempParamOut = '';
    FETCH NEXT FROM getinfo into @col
END


CLOSE getinfo
DEALLOCATE getinfo
RETURN 0

In the dynamic T-SQL statement you need to assigned the value of the SELECT to the variable. Also, sometimes this output value can be NULL but STRING + NULL equals to NULL. I added a buffer variable @TempParamOut for storing the intermediate results. You are using the @ParamOut variable and overwriting its value each time the dynamic T-SQL statement is executed. That's why no concatenation is performed at all.

Sign up to request clarification or add additional context in comments.

3 Comments

Other than a tiny glitch where it repeats the previous non-null column for a null column, it seems to work, thanks @gotqn!
@gotqn, If it finds NULLS it retains the value in @TempParamOut , so you just need to clear it after you set @ParamOut.. set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString; set @TempParamOut = '';
@ShaunGroenewald Thanks. I have changed it.
2

We usually get NULL as an output when there are NULL based appends (using plus(+) sign). In order to overcome, follow below steps,

  1. Print the dynamically created SQL statement and see what field is causing the issue
  2. Try replacing the NULL based values with empty string ('')

Comments

1

@gotqn already found your mistake - you're not assigning anything to your output variable.

But here is another approach without cursor and with single source table scan:

DECLARE
    @sql VARCHAR(MAX),
    @TableName VARCHAR(100) = 'dbo.MyTable'


SELECT @sql = 'SELECT STUFF(''''' +
    (
        SELECT 
            '
            +ISNULL(
                    MIN(CASE WHEN t.' + QUOTENAME (c.name) + ' IS NOT NULL AND LEN(t.' + QUOTENAME (c.name) + ') >= 1 THEN '', ' + QUOTENAME (c.name) + ''' ELSE '''' END)
                    , '''')'
        FROM sys.columns c
        WHERE c.[object_id] = t.[object_id]
        ORDER BY c.column_id
        FOR XML PATH(''), TYPE 
     ).value('.', 'VARCHAR(MAX)') + ', 1, 1, '''') FROM ' 
     + QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name) + ' as t'
FROM sys.tables t
WHERE t.object_id = object_id(@TableName, 'U')

print @sql

EXEC (@sql)

EXEC ('select top 10 * from ' + @TableName)

Note QUOTENAME function here - better use this in place of '[' + name + ']'. And of course objects may have different schema so filtering by name may not be a secure solution.

Comments

1

Going off @gotqn 's answer.

When I ran it, it didn't order the results properly and returned with too few row. Some of this was because of garbage values in the fields eg. " " and the checking was a bit off.

Changed it to IF EXISTS instead and where NOT NULL and Len > 0

ALTER PROCEDURE [dbo].[spGetTables] 
(
    @TableName    varchar(255)
,@ParamOut    varchar(2000) OUTPUT
)
AS

declare @CommaString varchar(max)
set @CommaString = ''

Declare @col varchar(255), @cmd nvarchar(max)
declare @colName varchar(2000)
SET @colName = ''

DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = @TableName 

OPEN getinfo

FETCH NEXT FROM getinfo into @col

DECLARE @TempParamOut varchar(2000) = '';

WHILE @@FETCH_STATUS = 0
BEGIN

    SELECT @cmd = 'IF EXISTS (SELECT top 1 * FROM [' + @TableName + '] WHERE [' + @col + '] IS NOT NULL and len(LTRIM(RTRIM(REPLACE(REPLACE(REPLACE([' + @col + '], CHAR(10), ''''), CHAR(13), ''''), CHAR(9), '''')))) > 0) BEGIN select  @Result=''' + @col + ','' END'

    exec sp_executesql @cmd, N'@Result varchar(max) out', @TempParamOut out

    set @ParamOut = ISNULL(@ParamOut,'') + ISNULL(@TempParamOut,'') + @CommaString;
    set @TempParamOut = '';

    FETCH NEXT FROM getinfo into @col
END

CLOSE getinfo
DEALLOCATE getinfo
RETURN 0

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.