在 SSRS 数据集定义中将 table 名称作为参数传递

Passing table name as a parameter in SSRS dataset definition

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

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 的可变内部参数,其中提取月份和年份以形成table 名称,例如“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;
'''

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

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

您还需要安全地注入动态对象的值。这给你类似下面的东西(注意这段代码中有几条注释,你应该根据需要检查和更改):

/*
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

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

注意,我强烈建议同时使用空格和换行符;正如我上面所做的那样。在您发布的区块中无法阅读您的动态声明。仅仅因为一个语句是动态的并不意味着你应该放弃 window.

的格式

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