我正在尝试生成一个SQL语句,该语句根据过滤器从数据库中动态获取列名。 我们有一个包含大约50列的表,每列都有一个前缀,表示它适用于哪个“集合”。我创建了一个在SQL Management Studio中运行良好的Query,但是由于我想在.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)
答案 0 :(得分:1)
您可以将查询包装在过程中。然后,您可以从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);
}
}
答案 1 :(得分:0)
您可以创建一个只包含该查询所需列的视图。当您在查询中所需的列发生更改时,您只需更新视图和中提琴,您的所有应用程序现在都可以获得所需的新列。您只需确保您的应用可以处理不同的潜在列。
答案 2 :(得分:0)
好的解决方案就是使用视图。
使用函数的另一个选项但我们无法在创建后更新函数。 这是一个例子。
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
所以使用View代替函数。
还有另一种创建新过程而非视图的最佳方法。 这是一个例子
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'