【问题标题】:Passing table name as a parameter in SSRS dataset definition在 SSRS 数据集定义中将表名作为参数传递
【发布时间】:2020-07-20 12:31:55
【问题描述】:

好的,所以我正在尝试添加一个可以动态创建表名并接受其他几个参数来检索所需输出的数据集。以下是我的数据集查询-

declare @cmd nvarchar(max)

select @cmd = 'select at.LocationID, at.LocationName as Location, er.company_name as Company, er.BranchShortCode as Branch, er.Department_Name as Department , 
at.UniqueEmpID, er.EmpName , er.Designation_Name ,convert(date,at.AttendanceDate) as AttendanceDate, at.StatusCode, 
substring(convert(varchar(20),convert(time,at.InTime)),1,8) as InTime, substring(convert(varchar(20),convert(time,at.OutTime)),1,8) as OutTime, 
at.ShiftFName as ShiftName, at.BeginTime as ShiftStartTime, at.EndTime  as ShiftEndTime
from ' + @TableName + ' as at inner join EmployeeAllDetail_Rpt er on at.UniqueEmpID = er.UniqueEmpID
where LocationID in (@LocationID) and er.company_id in (@Company_ID) 
and er.branch_id in (@Branch_ID) and er.dept_id in (@dept_ID) 
and convert(date,at.AttendanceDate) between convert(date,@FromDate) and convert(date,@ToDate)
and DATEDIFF(day,convert(date,@FromDate,103),convert(date,@ToDate,103)) <= 7
order by at.LocationID, er.company_name, er.BranchShortCode, er.Department_Name, at.AttendanceDate'

exec (@cmd)

现在@TableName 是一个基于@FromDate 的可变内部参数,其中它提取月份和年份以形成表格名称,例如“Attendance_072020”。

@LocationID/@CompanyID/@Branch_ID/@Dept_ID & @FromDate/@ToDate 是其他几个参数。

当我尝试使用上述查询刷新字段时,我得到一个“@LocationID”必须声明错误。

如果有人可以帮助或指导我朝着正确的方向前进,我将不胜感激。如果使用 SSRS 无法实现这一点,如果有人能简要说明我如何设计一个存储过程来实现同样的目标,我将非常感激。

更新:这是我现在在报告中使用的代码块 -

DECLARE @TableNamesql NVARCHAR(MAX),
        @SQL NVARCHAR(MAX),
        @Params NVARCHAR(MAX),
        @TableName NVARCHAR(128),
        @FromDate date,
        @ToDate date,
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10),
        @LocationID int,
        @Company_ID int,
        @Branch_ID int,
        @dept_ID int;

SET @Params = N'@LocationID int, @Company_ID int, @Branch_ID int, @dept_ID int, @FromDate date, @ToDate date';
--PRINT @Params


SET @TableNamesql = N'select @TableName = Tablename from (' + @CRLF +
                    N'select case when datepart(month,@FromDate) < 10 then ' + '''hrms_Attendance_0''' + ' + cast(datepart(month,@FromDate) as varchar) + ' + @CRLF +
                    N'cast(datepart(year,@FromDate) as varchar) ' + @CRLF +
                    N'else ' + '''hrms_Attendance_''' + ' + cast(datepart(month,@FromDate) as varchar) + cast(datepart(year,@FromDate) as varchar) end as Tablename)t';
--PRINT @TableNamesql

EXEC sys.sp_executesql @TableNamesql,N'@FromDate DATE, @TableName nvarchar(128) OUTPUT',@FromDate = @FromDate, @TableName = @TableName OUTPUT
--PRINT @TableName

SET @SQL = N'SELECT at.LocationID,' + @CRLF +
           N'       at.LocationName AS Location,' + @CRLF +
           N'       er.company_name AS Company,' + @CRLF +
           N'       er.BranchShortCode AS Branch,' + @CRLF +
           N'       er.Department_Name AS Department,' + @CRLF +
           N'       at.UniqueEmpID,' + @CRLF +
           N'       er.EmpName,' + @CRLF +
           N'       er.Designation_Name,' + @CRLF +
           N'       CONVERT(date, at.AttendanceDate) AS AttendanceDate,' + @CRLF +
           N'       at.StatusCode,' + @CRLF +
           N'       SUBSTRING(CONVERT(varchar(20), CONVERT(time, at.InTime)), 1, 8) AS InTime,' + @CRLF +
           N'       SUBSTRING(CONVERT(varchar(20), CONVERT(time, at.OutTime)), 1, 8) AS OutTime,' + @CRLF +
           N'       at.ShiftFName AS ShiftName,' + @CRLF +
           N'       at.BeginTime AS ShiftStartTime,' + @CRLF +
           N'       at.EndTime AS ShiftEndTime' + @CRLF +
           N'FROM dbo.' + QUOTENAME(@TableName) + N' at' + @CRLF + 
           N'  INNER JOIN EmployeeAllDetail_Rpt er ON at.UniqueEmpID = er.UniqueEmpID' + @CRLF +
           N'WHERE LocationID IN (@LocationID)' + @CRLF +
           N'  AND er.company_id IN (@Company_ID)' + @CRLF +
           N'  AND er.branch_id IN (@Branch_ID)' + @CRLF +
           N'  AND er.dept_id IN (@dept_ID)' + @CRLF +
           N'  AND at.AttendanceDate >= @FromDate' + @CRLF +
           N'  AND at.AttendanceDate < DATEADD(DAY, 1, @ToDate)' + @CRLF + 
           N'  AND DATEDIFF(DAY, @FromDate, @ToDate) <= 7' + @CRLF +
           N'ORDER BY at.LocationID,' + @CRLF +
           N'         er.company_name,' + @CRLF +
           N'         er.BranchShortCode,' + @CRLF +
           N'         er.Department_Name,' + @CRLF +
           N'         er.UniqueEmpID,' + @CRLF +
           N'         at.AttendanceDate;';
--PRINT @SQL

EXEC sys.sp_executesql @SQL, @Params, @LocationID, @Company_ID, @Branch_ID, @dept_ID, @FromDate, @ToDate;
'''

【问题讨论】:

  • 你想要这样做的事实表明你有整体设计缺陷。

标签: sql-server reporting-services ssrs-2012 reportbuilder3.0


【解决方案1】:

正如我在 cmets 中提到的,您需要这样的查询这一事实表明您存在设计缺陷。如果您有多个表都具有相同的定义,那么这可能意味着您有一个非规范化设计并且需要真正修复它。

至于回答这个问题,这就是为什么你不应该使用EXEC (@SQL);你不能参数化语句。变量/参数仅存在于它们声明的范围内。它们不会存在于动态语句中,因为那是一个单独的范围。这就是为什么您应该始终使用对sys.sp_executesql参数化调用。

您还需要安全地注入动态对象的值。这为您提供了如下所示的内容(请注意,此代码中有几个 cmets 您应该根据需要检查和更改):

/*
Other pamaraters will have been previously declared, however, I assume the following datatypes:
@TableName sysname
@LocationID int
@Company_ID int
@Branch_ID int
@dept_ID int
@FromDate date
@ToDate date
*/

DECLARE @SQL nvarchar(MAX),
        @Params nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

--I may have missed some out here, and I have GUESSED data types
SET @Params = N'@LocationID int, @Company_ID int, @Branch_ID int, @dept_ID int, @FromDate date, @ToDate date';

SET @SQL = N'SELECT at.LocationID,' + @CRLF +
           N'       at.LocationName AS Location,' + @CRLF +
           N'       er.company_name AS Company,' + @CRLF +
           N'       er.BranchShortCode AS Branch,' + @CRLF +
           N'       er.Department_Name AS Department,' + @CRLF +
           N'       at.UniqueEmpID,' + @CRLF +
           N'       er.EmpName,' + @CRLF +
           N'       er.Designation_Name,' + @CRLF +
           N'       CONVERT(date, at.AttendanceDate) AS AttendanceDate,' + @CRLF +
           N'       at.StatusCode,' + @CRLF +
           N'       SUBSTRING(CONVERT(varchar(20), CONVERT(time, at.InTime)), 1, 8) AS InTime,' + @CRLF +
           N'       SUBSTRING(CONVERT(varchar(20), CONVERT(time, at.OutTime)), 1, 8) AS OutTime,' + @CRLF +
           N'       at.ShiftFName AS ShiftName,' + @CRLF +
           N'       at.BeginTime AS ShiftStartTime,' + @CRLF +
           N'       at.EndTime AS ShiftEndTime' + @CRLF +
           N'FROM dbo.' + QUOTENAME(@TableName) + N' at' + @CRLF + --Guessed Schema
           N'     INNER JOIN EmployeeAllDetail_Rpt er ON at.UniqueEmpID = er.UniqueEmpID' + @CRLF +
           N'WHERE LocationID IN (@LocationID)' + @CRLF +
           N'  AND er.company_id IN (@Company_ID)' + @CRLF +
           N'  AND er.branch_id IN (@Branch_ID)' + @CRLF +
           N'  AND er.dept_id IN (@dept_ID)' + @CRLF +
           --Considering I have assumed that @FromDate and @ToDate are dates, there is no need to convert them.
           --You should also be using >= and < logic here, so I assume what you actually want is this:
           N'  AND at.AttendanceDate >= @FromDate' + @CRLF +
           N'  AND at.AttendanceDate < DATEADD(DAY, 1, @ToDate)' + @CRLF + 
           --This seems an odd clause to have in the WHERE.
           --Again, considering I have assumed that @FromDate and @ToDate are dates, there is no need to convert them.
           N'  AND DATEDIFF(DAY, @FromDate, @ToDate) <= 7' + @CRLF +
           N'ORDER BY at.LocationID,' + @CRLF +
           N'         er.company_name,' + @CRLF +
           N'         er.BranchShortCode,' + @CRLF +
           N'         er.Department_Name,' + @CRLF +
           N'         at.AttendanceDate;';

--PRINT @SQL; --Your best friend.

EXEC sys.sp_executesql @SQL, @Params, @LocationID, @Company_ID, @Branch_ID, @dept_ID, @FromDate, @ToDate; --If I missed any parameters, you need to add these

您可以使用“最好的朋友”来帮助调试。

注意,我强烈建议同时使用空格和换行符;正如我在上面所做的那样。您发布的块中无法阅读您的动态声明。仅仅因为语句是动态的并不意味着您应该将格式排除在窗口之外。

我在我的文章Dos and Don'ts of Dynamic SQL 中详细介绍了动态 SQL 和良好实践。

【讨论】:

  • 对迟到的回复表示歉意,但感谢这个解决方案对我有很大帮助。然而,尽管代码在 SQL Server 上运行良好,但它确实在 SSRS 中引发了未知异常。我很确定我遗漏了一些清晰明了的东西。
  • 由于语句是动态的,@JaiKumar ,SSRS 不能在没有参数的情况下运行查询;所以无法确定结果集。当您将其添加为数据集时,它会要求您提供一些输入参数;输入一些有效的值,SSRS 将获得定义。否则,您需要在 SSRS 中手动定义数据集。
  • ``SET @TableNamesql = N'select @TableName = Tablename from (' + @CRLF + N'select case when datepart(month,@FromDate)
  • 好的,所以我使用上述语句将 tablename 值分配给变量,并且在刷新字段时我收到此错误 - “变量名'@TableName'已经被声明。变量名必须是在查询批处理或存储过程中是唯一的。”
  • 我没有在我的查询 @JaiKumar 中声明 @TableName,我假设您已将其声明为参数(在 SP 中,报告?)。如果您添加了声明,那么这似乎是问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 2014-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多