SQL 具有动态列名的存储过程

SQL Stored Procedure with Dynamic Column Names

我正在尝试生成一个 SQL 语句,该语句基于过滤器从数据库中动态获取列名。 我们有一个包含大约 50 列的 table,每列都有一个前缀来表示它适用于哪个 "set"。我创建了一个在 SQL Management Studio 中运行良好的查询,但由于我想在 .Net 应用程序和 Web 应用程序中使用结果,所以最好有一个存储过程或类似的东西我可以要求结果。我知道我可以在查询中手动指定列,但我想尝试动态执行此操作,可能会添加列。我已经计算出的查询如下,将其存储在我的 SQL 服务器中以便我可以根据需要使用它的最佳方式是什么?

DECLARE @ColumnList AS Varchar(MAX)
DECLARE @StartDate as Date
DECLARE @EndDate as Date
DECLARE @DepartmentID as Varchar(10)
DECLARE @ColumnFilter as Varchar(3)

SET @StartDate = '2015-01-01' 
SET @EndDate = '2015-05-01'
SET @DepartmentID = 'GMC'
SET @ColumnFilter = 'GM'

SELECT @ColumnList =  COALESCE(@ColumnList, ',') + c.name+',' FROM sys.columns c
WHERE c.object_id = OBJECT_ID('tblDetails') AND c.Name LIKE @ColumnFilter + '%'

SET @ColumnList = Left(@ColumnList,Len(@ColumnList)-1)

DECLARE @Template AS Varchar(max)
SET @Template = 'SELECT [RecordID]
      ,[DateRecord]
      ,[DepartmentID]
      ,[Shift]
      ,[ShiftLength]
      ,[ShiftType]
      ,[Active]
      ,[Comment]
      {ColumnList}
  FROM [Data_Warehouse].[dbo].[tblDetails]
  WHERE DateRecord >= ''{StartDate}'' AND DateRecord <= ''{EndDate}'' AND DepartmentID = ''{DepartmentID}''
  ORDER BY DateRecord'

SET @Template = REPLACE(@Template, '{ColumnList}', @ColumnList) 
SET @Template = REPLACE(@Template, '{StartDate}', @StartDate) 
SET @Template = REPLACE(@Template, '{EndDate}', @EndDate) 
SET @Template = REPLACE(@Template, '{DepartmentID}', @DepartmentID ) 

EXEC (@Template)

您可以创建一个视图,其中仅包含该查询所需的列。当您想要在查询中更改的列时,您只需更新视图,然后中提琴,您的所有应用程序现在都会获得您想要的新列。您只需确保您的应用可以处理返回的不同潜在列。

好的解决方案是为此使用视图。

另一个使用函数的选项,但我们无法在创建后更新函数。 这是一个例子。

CREATE FUNCTION V_GetWarehouse (@StartDate Date,@EndDate Date,@DepartmentID  varchar(10))
RETURNS TABLE
AS
RETURN
 SELECT [RecordID]
  ,[DateRecord]
  ,[DepartmentID]
  ,[Shift]
  ,[ShiftLength]
  ,[ShiftType]
  ,[Active]
  ,[Comment]      
FROM [Data_Warehouse].[dbo].[tblDetails]
 WHERE DateRecord >= @StartDate AND DateRecord <= @EndDate AND DepartmentID=@DepartmentID

所以使用视图而不是函数。

还有另一种创建新过程而不是视图的最佳方法。 举个例子

CREATE PROCEDURE sp_GetGenrealResult
 @ColumnName text,
 @TableName varchar(1000),
 @StartDate Date,
 @EndDate Date,
 @DepartmentID  varchar(10)
  AS
enter code here
        BEGIN

     declare @DateRecordCol char(10)='DateRecord',
      @DepartmentIDCol char(12)='DepartmentID' 
     Select @ColumnName from @TableName where @DateRecordCol >= @StartDate AND @DateRecordCol <= @EndDate AND @DepartmentIDCol =@DepartmentID
    END

执行这个。

   EXEC sp_GetGenrealResult '[RecordID],[DateRecord],  [DepartmentID]', '[Data_Warehouse].[dbo].  [tblDetails]' , '2015-01-01', '2015-05-01' ,'GMC'

您可以按原样将查询包装在过程中。然后你可以从你的 app/web 执行它并得到一个 DataTable 作为结果。当您将 DataTable 绑定到 DataGrid 时,它应该自动呈现 DataGrid

中的列
CREATE PROCEDURE GetDynamicReport

     @StartDate as Date
    ,@EndDate as Date
    ,@DepartmentID as Varchar(10)
    ,@ColumnFilter as Varchar(3)
AS
BEGIN
    DECLARE @ColumnList AS Varchar(MAX)

    SELECT @ColumnList =  COALESCE(@ColumnList, ',') + c.name+',' FROM sys.columns c
    WHERE c.object_id = OBJECT_ID('tblDetails') AND c.Name LIKE @ColumnFilter + '%'

    SET @ColumnList = Left(@ColumnList,Len(@ColumnList)-1)

    DECLARE @Template AS Varchar(max)
    SET @Template = 'SELECT [RecordID]
          ,[DateRecord]
          ,[DepartmentID]
          ,[Shift]
          ,[ShiftLength]
          ,[ShiftType]
          ,[Active]
          ,[Comment]
          {ColumnList}
      FROM [dbo].[tblDetails]
      WHERE DateRecord >= ''{StartDate}'' AND DateRecord <= ''{EndDate}'' AND DepartmentID = ''{DepartmentID}''
      ORDER BY DateRecord'

    SET @Template = REPLACE(@Template, '{ColumnList}', @ColumnList) 
    SET @Template = REPLACE(@Template, '{StartDate}', @StartDate) 
    SET @Template = REPLACE(@Template, '{EndDate}', @EndDate) 
    SET @Template = REPLACE(@Template, '{DepartmentID}', @DepartmentID ) 

    EXEC (@Template);

END

GO
-- Execute it like this
EXEC dbo.GetDynamicReport 
    @StartDate = '2015-06-03 06:38:07',
    @EndDate = '2015-06-03 06:38:07',
    @DepartmentID = 'abc',
    @ColumnFilter = 'GM'

调用程序

public static DataTable CallReportProcedure(string connectionString, DateTime startDate, DateTime endDate, string departmentID, string columnFilter)
{
    using(var conn = new SqlConnection(connectionString))
    using(var cmd = new SqlCommand("GetDynamicReport", conn) 
        { CommandType = System.Data.CommandType.StoredProcedure} )
    {
        cmd.Parameters.AddWithValue("@StartDate", startDate);
        cmd.Parameters.AddWithValue("@EndDate", endDate);
        cmd.Parameters.AddWithValue("@DepartmentID", departmentID);
        cmd.Parameters.AddWithValue("@ColumnFilter", columnFilter);

        var da = new SqlDataAdapter(cmd);
        var ds = new DataSet();
        da.Fill(ds);
        return ds.Tables[0];
    }
}

然后,如果您确实需要了解有关列的信息,您可以检查生成的 DataTable

static void Main(string[] args)
        {
            SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
            builder.DataSource = "localhost";
            builder.InitialCatalog = "peter";
            builder.IntegratedSecurity = true;
            var connectionString = builder.ConnectionString;

            var resultTable = p.CallReportProcedure(connectionString, new DateTime(2015, 1, 1), new DateTime(2015, 5, 1), "GMC", "GM");
            // Bind the resultTable to your DataGrid

            // If you need to know the column names then you can loop through the Columns of the resultTable
            foreach (DataColumn col in resultTable.Columns)
            {
                // Print the names of the columns from the result
                Console.WriteLine(col.ColumnName);
            }
        }