【问题标题】:tsql procedure return values asp.nettsql 过程返回值 asp.net
【发布时间】:2018-06-09 08:06:05
【问题描述】:

我正在尝试做的事情:我创建了一个 T-SQL 存储过程,它从多个表中返回单个列。

CREATE PROCEDURE [dbo].[Search_] 
    (@am VARCHAR(12)) 
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @DBName VARCHAR(128)

    DECLARE Tbl CURSOR READ_ONLY FOR
         SELECT LEFT(TABLE_NAME, 27) AS Tbl 
         FROM ap.INFORMATION_SCHEMA.TABLES 
         WHERE TABLE_NAME LIKE LEFT('STORED_PRODUCTS_FR_[0-9]_%', 27)
           AND SUBSTRING(TABLE_NAME, 20, 2) LIKE '%[0-9]%'
           AND SUBSTRING(TABLE_NAME, 23, 1) = '_'
         ORDER BY
             CONVERT(INT, SUBSTRING(TABLE_NAME, 24, 4)) ASC,
             CONVERT(INT, SUBSTRING(TABLE_NAME, 21, 2)) ASC

    OPEN Tbl

    FETCH NEXT FROM Tbl INTO @DBName

    WHILE @@FETCH_STATUS = 0
    BEGIN
        DECLARE @SQL VARCHAR(100)
        SET @sql = 'SELECT [column 3] FROM ' + @DBName + ' WHERE [COLUMN 4] = ' + @am + '';

        EXEC(@sql)

        FETCH NEXT FROM Tbl INTO @DBName
    END
END

CLOSE Tbl
DEALLOCATE Tbl

然后在asp.net中,我想填充一个gridview...

try
{
    SqlDataAdapter dt = new SqlDataAdapter();

    string message = string.Empty;
    con.Open();

    cmd.CommandText = "Search_";
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@am", am.Text);   
    cmd.Connection = con;

    dt.SelectCommand = cmd;
    DataTable dTable = new DataTable();
    dt.Fill(dTable);

    GridView1.DataSource = dTable;
    GridView1.DataBind();
}
catch (Exception ex)
{
    throw ex;
}

只返回存储过程的单行(第一行)。

我做错了什么?似乎这些值正在覆盖自己。

任何人的帮助......

【问题讨论】:

  • 您的 SP 在 SQL Server 中是否如您所愿?
  • 是的。它按预期返回 2 行。
  • 在 SQL 管理工作室中运行你的存储过程,看看那里的数据是如何返回的。您可能有两张单行表,而不是一张两行表
  • 此代码将为每个结果返回一个 DataTable,并最终仅将第一个表与它的唯一结果绑定到您的 DataGrid 中
  • 我发布的不是 2 行,而是 3 行。我没有注意到最后一行。前 2 行有值。最后一个被命名为“返回值”,值为 0。

标签: c# sql-server tsql stored-procedures


【解决方案1】:

您的存储过程返回两行,但由于在不同的选择语句中选择了每一行,DataAdapter 只能使用返回的第一行来填充DataTable。如果您在哪里填写 DataSet,它将包含 2 个 DataTable 实例。

请注意,您的存储过程表明您的数据库设计存在缺陷 - 拥有多个存储相同类型实体的表对于数据库来说是一个糟糕的设计。但是,我不确定这里的情况。

无论如何,要通过快速补丁解决此问题,您可以将程序更改为以下内容:

CREATE PROCEDURE [dbo].[Search_] (@am varchar(12)) 
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @DBName varchar(128)
    declare @SQL varchar(max) = ''

    DECLARE Tbl CURSOR READ_ONLY FOR
    select LEFT(TABLE_NAME,27) as Tbl from ap.INFORMATION_SCHEMA.TABLES 
    where TABLE_NAME like left('STORED_PRODUCTS_FR_[0-9]_%',27)
    and SUBSTRING(TABLE_NAME , 20,2) like '%[0-9]%'
    and SUBSTRING(TABLE_NAME , 23,1) = '_'
    order by CONVERT(int , substring(TABLE_NAME,24,4)) asc ,
    CONVERT(int , substring(TABLE_NAME,21,2)) asc   

    OPEN Tbl

    FETCH NEXT FROM Tbl INTO @DBName
    WHILE @@FETCH_STATUS = 0
    BEGIN
        set @sql += 'union all select [column 3] from '+@DBName+' WHERE [COLUMN 4] ='+@am+' ';
        FETCH NEXT FROM Tbl INTO @DBName
    END

    CLOSE Tbl
    DEALLOCATE Tbl

    SET @sql = STUFF(@Sql, 1, 10, '') -- Remove the first union all
    exec(@sql)
END

【讨论】:

  • 我只是测试它并且它有效..上述解决方案像魅力一样工作..谢谢
  • 很高兴为您提供帮助 ;-)
【解决方案2】:

在你的脚本中,最后一个end 应该放在DEALLOCATE Tbl 之后,并且为了调用返回多个记录集的sp 更好地使用DataSet 或DataReader:

var dataset = new DataSet();
using(var cnnn = new SqlConnection(cnnString))
{
    var adapter = new SqlDataAdapter();
    adapter.SelectCommand = new SqlCommand("dbo.Search_", cnnn);
    adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
    adapter.Fill(dataset);
}
dataset.Tables => gives u all the results of exec(@sql)

由于每个结果集都返回相同的列名和结构,因此您可以将它们全部合并到一个 tb 中:

var allTbs = dataset.Tables[0].Copy();
for(int i = 1; i < dataset.Tables.Count; i++)
    allTbs.Merge(dataset.Tables[i]);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 2014-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多