2011-01-23 533 views
1

我有以下存储过程,并且如果我们在SQL分析器上执行此操作,它将返回记录没有任何问题。但是,如果我通过ASP.NET执行此操作(我正在使用EntitySpace对象)来将此查询生成到数据表中并且它说:“Cursorfetch:在INTO列表中声明的变量数必须与所选列的变量数相匹配。”Cursorfetch:在INTO列表中声明的变量数量必须与选定列的变量数量相匹配

我已经与EntitySpace团队讨论过这个问题,他们说这是查询问题?!?!任何想法家伙?我们坚持这个问题,任何指导或提示都会很好。

我们使用的环境: .NET 4 EntitySpace 2010 SQL Server 2005数据库

ALTER PROCEDURE [dbo].[rpt_CPRRespondListReport] 
(
@SurveyID INT 
) 
AS 
BEGIN 
SET NOCOUNT ON; 
SET FMTONLY OFF; 

DECLARE @SID INT; 

SELECT @SID = sid 
FROM lime_Surveys 
WHERE sid = @SurveyID 

IF (@SID > 1) 
BEGIN 

    DECLARE @T TABLE 
    (
     RecID INT, 
     RecID2 INT, 
     RecID3 INT, 
     RecID4 INT, 
     FirstName VARCHAR(40), 
     LastName VARCHAR(40), 
     Email VARCHAR(320), 
     QuestionName VARCHAR(100), 
     QuestionValue1 VARCHAR(5), 
     QuestionValue2 VARCHAR(5), 
     QuestionValue3 VARCHAR(1000), 
     QuestionValue4 VARCHAR(5) 
    ); 

    DECLARE @ColumnNameRow VARCHAR(MAX); 
    DECLARE @Column_name VARCHAR(32); 

    DECLARE @sqlstatement1 NVARCHAR(MAX) 
    SET @sqlstatement1 = 'DECLARE QuestionCursor CURSOR FOR ' +  
          'SELECT column_name ' + 
          'FROM information_schema.columns (NOLOCK) ' + 
          'WHERE table_name = ''lime_survey_' + CAST(@SurveyID AS VARCHAR) + ''' AND Ordinal_position >= 10 ' + 
          'ORDER BY ordinal_position ASC' 

    EXEC sp_executesql @sqlstatement1 

    SET @ColumnNameRow = ''; 

    OPEN QuestionCursor 
    FETCH NEXT FROM QuestionCursor 
    INTO @Column_name 

    WHILE @@FETCH_STATUS = 0 
    BEGIN  
     SET @ColumnNameRow = @ColumnNameRow + '[' + @Column_Name + ']' + ', ' 

     FETCH NEXT 
     FROM QuestionCursor 
     INTO @Column_name 
    END 

    SET @ColumnNameRow = SUBSTRING(@ColumnNameRow, 1, LEN(@ColumnNameRow) - 1); 

    CLOSE QuestionCursor 
    DEALLOCATE QuestionCursor 

    DECLARE @tid INT; 
    DECLARE @FirstName VARCHAR(40); 
    DECLARE @LastName VARCHAR(40); 
    DECLARE @Email VARCHAR(320); 
    DECLARE @Q010101 VARCHAR(5); 
    DECLARE @Q010102 VARCHAR(5); 
    DECLARE @Q010103 VARCHAR(1000); 
    DECLARE @Q010201 VARCHAR(5); 
    DECLARE @Q010202 VARCHAR(5); 
    DECLARE @Q010203 VARCHAR(1000); 
    DECLARE @Q010301 VARCHAR(5); 
    DECLARE @Q010302 VARCHAR(5); 
    DECLARE @Q010303 VARCHAR(1000); 
    DECLARE @Q010401 VARCHAR(5); 
    DECLARE @Q010402 VARCHAR(5); 
    DECLARE @Q010403 VARCHAR(1000); 
    DECLARE @Q010501 VARCHAR(5); 
    DECLARE @Q010502 VARCHAR(5); 
    DECLARE @Q010503 VARCHAR(1000); 
    DECLARE @Q010601 VARCHAR(5); 
    DECLARE @Q010602 VARCHAR(5); 
    DECLARE @Q010603 VARCHAR(1000); 
    DECLARE @Q010701 VARCHAR(5); 
    DECLARE @Q010702 VARCHAR(5); 
    DECLARE @Q010703 VARCHAR(1000); 
    DECLARE @Q010801 VARCHAR(5); 
    DECLARE @Q010802 VARCHAR(5); 
    DECLARE @Q010803 VARCHAR(1000); 
    DECLARE @Q010901 VARCHAR(5); 
    DECLARE @Q010902 VARCHAR(5); 
    DECLARE @Q010903 VARCHAR(1000); 
    DECLARE @Q011001 VARCHAR(5); 
    DECLARE @Q011002 VARCHAR(5); 
    DECLARE @Q011003 VARCHAR(1000); 
    DECLARE @Q011101 VARCHAR(5); 
    DECLARE @Q011102 VARCHAR(5); 
    DECLARE @Q011103 VARCHAR(1000); 
    DECLARE @Q011201 VARCHAR(5); 
    DECLARE @Q011202 VARCHAR(5); 
    DECLARE @Q011203 VARCHAR(1000); 
    DECLARE @Q011301 VARCHAR(5); 
    DECLARE @Q011303 VARCHAR(1000); 


    DECLARE @sqlstatement2 NVARCHAR(MAX) 
    SET @sqlstatement2 = 'DECLARE SURVEY_RESULT_CURSOR CURSOR FOR 
          SELECT tid, FirstName, LastName, Email, ' + @ColumnNameRow + ' 
          FROM dbo.lime_tokens_' + CAST(@SurveyID AS VARCHAR) + ' a (NOLOCK) INNER JOIN lime_survey_' + CAST(@SurveyID AS VARCHAR) + ' b (NOLOCK) ON a.token = b.token 
          where Completed IS NOT NULL' 

    EXEC sp_executesql @sqlstatement2 

    OPEN SURVEY_RESULT_CURSOR 
    FETCH NEXT FROM SURVEY_RESULT_CURSOR 
    INTO @tid, @FirstName, @LastName, @Email, 
     @Q010101, @Q010102, @Q010103, @Q010201, @Q010202, @Q010203, @Q010301, @Q010302, @Q010303, @Q010401, @Q010402, @Q010403, 
     @Q010501, @Q010502, @Q010503, @Q010601, @Q010602, @Q010603, @Q010701, @Q010702, @Q010703, @Q010801, @Q010802, @Q010803, 
     @Q010901, @Q010902, @Q010903, @Q011001, @Q011002, @Q011003, @Q011101, @Q011102, @Q011103, @Q011201, @Q011202, @Q011203, 
     @Q011301, @Q011303 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     INSERT INTO @T(RecID, RecID2, RecID3, RecID4, FirstName, LastName, Email, QuestionName, QuestionValue1, QuestionValue2, QuestionValue3) 
     SELECT @tid, 1, 1, 1, @FirstName, @LastName, @Email, 'Mobile Voice Coverage', @Q010101, @Q010102, @Q010103 
     UNION 
     SELECT @tid, 1, 2, 1, @FirstName, @LastName, @Email, 'Mobile Data Coverage', @Q010201, @Q010202, @Q010203 
     UNION 
     SELECT @tid, 1, 3, 1, @FirstName, @LastName, @Email, 'Mobile Voice Costs', @Q010301, @Q010302, @Q010303 
     UNION 
     SELECT @tid, 1, 4, 1, @FirstName, @LastName, @Email, 'Mobile Data Costs', @Q010401, @Q010402, @Q010403 
     UNION 
     SELECT @tid, 1, 5, 1, @FirstName, @LastName, @Email, 'International Roaming Costs', @Q010501, @Q010502, @Q010503 
     UNION 
     SELECT @tid, 1, 6, 1, @FirstName, @LastName, @Email, 'Handset Quality', @Q010601, @Q010602, @Q010603 
     UNION 
     SELECT @tid, 1, 7, 1, @FirstName, @LastName, @Email, 'Mobile Capped Plans', @Q010701, @Q010702, @Q010703 
     UNION 
     SELECT @tid, 1, 8, 1, @FirstName, @LastName, @Email, 'Message Bank/Voicemail', @Q010801, @Q010802, @Q010803 
     UNION 
     SELECT @tid, 1, 9, 1, @FirstName, @LastName, @Email, 'SMS', @Q010901, @Q010902, @Q010903 
     UNION 
     SELECT @tid, 1, 10, 1, @FirstName, @LastName, @Email, 'Mobile Internet/Email Account', @Q011001, @Q011002, @Q011003 
     UNION 
     SELECT @tid, 1, 11, 1, @FirstName, @LastName, @Email, 'Access to our office intranet', @Q011101, @Q011102, @Q011103 
     UNION 
     SELECT @tid, 1, 12, 1, @FirstName, @LastName, @Email, 'Account Management', @Q011201, @Q011202, @Q011203 
     UNION 
     SELECT @tid, 1, 13, 3, @FirstName, @LastName, @Email, 'Current Provider', @Q011301, null, @Q011303 

    FETCH NEXT FROM SURVEY_RESULT_CURSOR 
    INTO @tid, @FirstName, @LastName, @Email, 
     @Q010101, @Q010102, @Q010103, @Q010201, @Q010202, @Q010203, @Q010301, @Q010302, @Q010303, @Q010401, @Q010402, @Q010403, 
     @Q010501, @Q010502, @Q010503, @Q010601, @Q010602, @Q010603, @Q010701, @Q010702, @Q010703, @Q010801, @Q010802, @Q010803, 
     @Q010901, @Q010902, @Q010903, @Q011001, @Q011002, @Q011003, @Q011101, @Q011102, @Q011103, @Q011201, @Q011202, @Q011203, 
     @Q011301, @Q011303 

    END 
    CLOSE SURVEY_RESULT_CURSOR 
    DEALLOCATE SURVEY_RESULT_CURSOR 

    SELECT RecID, RecID2, RecID3, RecID4, FirstName, LastName, Email, QuestionName, b.Title AS QuestionValue1, 
      b2.Title AS QuestionValue2, QuestionValue3 
    FROM @T a LEFT OUTER JOIN lime_labels b (NOLOCK) ON a.QuestionValue1 = b.Code 
      LEFT OUTER JOIN lime_labels b2 (NOLOCK) ON a.QuestionValue2 = b2.Code 
    ORDER BY RecID ASC, RecID2 ASC, RecID3 ASC 

END 
END 
+0

这看起来像是你可能使用`UNPIVOT`的。它仍然需要动态SQL,但我认为代码会更简单。 – 2011-01-23 23:02:05

回答

2

你的问题是与光标SURVEY_RESULT_CURSOR与列的变量数定义的事实

'DECLARE SURVEY_RESULT_CURSOR CURSOR FOR 
SELECT tid, FirstName, LastName, Email, ' + @ColumnNameRow + ' 

而FETCH .. INTO子句具有要插入的列的固定列表

FETCH NEXT FROM SURVEY_RESULT_CURSOR 
INTO @tid, @FirstName, @LastName, @Email, 
    @Q010101, @Q010102, @Q010103, @Q010201, @Q010202, @Q010203, @Q010301, @Q010302, @Q010303, @Q010401, @Q010402, @Q010403, 
    @Q010501, @Q010502, @Q010503, @Q010601, @Q010602, @Q010603, @Q010701, @Q010702, @Q010703, @Q010801, @Q010802, @Q010803, 
    @Q010901, @Q010902, @Q010903, @Q011001, @Q011002, @Q011003, @Q011101, @Q011102, @Q011103, @Q011201, @Q011202, @Q011203, 
    @Q011301, @Q011303 

当这两个计数不匹配时,您将得到该错误。

想想是否应该是一个静态计数(甚至不需要QuestionCursor)或重新考虑你的做法(也许动态SQL)

编辑:你仍然可以保持读取到变量列表从SURVEY_RESULT_CURSOR固定,两个条件

  1. 的变量的列表是等于或大于将产生被填充到全列计数时每次使用
  2. 可变@ColumnNameRow的最大列数多。

对于2,不难计数有多少个逗号(假设列名没有逗号),然后根据需要追加尽可能多的cast(NULL as varchar(5)) dummcol1, ..。将varchar(5)转换为varvar(1000)的@var将工作得很好。

要计算逗号:

set @commacount = len(@ColumnNameRow) - len(replace(@ColumnNameRow,',','')) 
+0

挑战在于我们正在处理表格,根据数据,潜在的字段名称不同。这就是为什么我们必须这样做。我们知道这将是相同数量的领域。但我想我可以使用通用字段名填充数据,然后将其用于光标后面。无论如何,我会尝试这种方法,并感谢您指出我。 – dcpartners 2011-01-24 00:01:19