我根据报告类型进行了一系列查询。为简单起见,这是我正在尝试做的一个例子:
If @Reporttype = '1'
Select lcustomerid, lname, fname
from customers
Where dtcreated > @startdate
Else if @Reporttype = '2'
Select barcode, lname, fname
from employees
where dtcreated > @startdate
Else if @reporttype = '3'
Select thetime, lname, name, barcode, lcustomerid
from Customers
where dtcreated > @startdate
根据传递的报告类型,您会注意到我运行了3个单独的查询。您还会注意到我正在返回不同的列和列数。
我想将它设为存储函数,并根据我传递的报告类型返回我需要的列。但是,我知道由于列数和列名不同 - 这不会像我希望的那样作为存储函数工作。
这里的主要问题是报告此信息 - 我不想拥有单独的功能,因为我必须为每种报告类型维护不同的报告。
我有办法让这项工作成功吗?
答案 0 :(得分:7)
您可以使用多语句功能,但需要指定将由3个select语句返回的所有列。似乎不可能返回多个结果集。
用户定义的函数不能返回多个结果集。用一个 存储过程如果需要返回多个结果集。 https://msdn.microsoft.com/en-us/library/ms191320.aspx
这是一个不便,但在报告中,您只能使用您需要的列,其他列将为空。
CREATE FUNCTION MyFun
(
@Reporttype int,
@startdate datetime
)
RETURNS
@Result TABLE
(
lcustomerid int,
lname nvarchar(50),
fname nvarchar(50),
barcode int,
thetime datetime,
name nvarchar(50)
)
AS
BEGIN
If @Reporttype = '1'
insert into @Result (lcustomerid, lname, fname)
select lcustomerid, lname, fname
from customers
Where dtcreated > @startdate
Else if @Reporttype = '2'
insert into @Result (barcode, lname, fname)
Select barcode, lname, fname
from employees
where dtcreated > @startdate
Else if @reporttype = '3'
insert into @Result (thetime, lname, name, barcode, lcustomerid)
Select thetime, lname, name, barcode, lcustomerid
from customers
where dtcreated > @startdate
RETURN
END
所以,你可以用这种方式调用函数
SELECT * FROM dbo.MyFun (1, getdate())
答案 1 :(得分:0)
在SQL中很难创建类似于通用或抽象的东西,特别是当它与SELECT of colums有关时。如果您的目的是编写尽可能少的代码,以便轻松维护sql脚本,并且能够在将来添加新的报表类型,只需稍作更改,我建议使用带有动态sql的存储过程。当您将SELECT视为动态时,您无法使用函数,这是错误的方法。我会写那样的东西
CREATE PROCEDURE MyProcedure
(
@ReportType int,
@startdate datetime
)
AS
BEGIN
DECLARE @colNames varchar(MAX),@tblName varchar(MAX),@sSQL varchar(MAX);
SELECT @colNames = CASE
WHEN @ReportType = 1 THEN
'lcustomerid, lname, fname' --You can also add alias
WHEN @ReportType = 2 THEN
'barcode, lname, fname'
WHEN @ReportType = 3 THEN
'thetime, lname, name, barcode, lcustomerid'
ELSE
RAISEERROR('Error msg');
END,
@tblName = CASE
WHEN @ReportType = 1 OR @ReportType = 3 THEN
'customers' --You can also add alias
WHEN @ReportType = 2 THEN
'employees'
ELSE
RAISEERROR('Error msg');
END
SET @sSQL =
'Select '+@colNames+'
from '+@tblName +'
where dtcreated > '''+CONVERT(varchar(10), @startdate, 121)+''''
EXEC(@sSQL)
END
你会将其称为
EXEC MyProcedure 1,'20170131'
例如,使用此代码每次需要新的报告类型时,您需要添加另一行以防所需的列名称。我使用这种方式处理Crystal报表,我认为这是最好的解决方案
答案 2 :(得分:0)
如果您无法使用存储过程并且需要使用某个功能,则可以UNPIVOT
数据,而不是client side
中的数据PIVOT
。
当不同数量的列返回到SQL Server Reporting Services
报告时,我需要执行类似的操作。例如,以下代码始终返回三列 - RowID
,Column
,Value
:
DECLARE @Table01 TABLE
(
[ID] INT
,[Value01] INT
,[Value02] NVARCHAR(256)
,[Value03] SMALLINT
);
DECLARE @Table02 TABLE
(
[ID] INT
,[Value01] INT
);
INSERT INTO @Table01 ([ID], [Value01], [Value02], [Value03])
VALUES (1, 111, '1V2', 7)
,(2, 222, '2V2', 8)
,(3, 333, '3V2', 9);
INSERT INTO @Table02 ([ID], [Value01])
VALUES (1, 111)
,(2, 222)
,(3, 333);
-- your function starts here
DECLARE @Mode SYSNAME = 'Table01' -- try with 'Table02', too
DECLARE @ResultSet TABLE
(
[RowID] INT
,[Column] SYSNAME
,[Value] NVARCHAR(128)
);
IF @Mode = 'Table01'
BEGIN;
INSERT INTO @ResultSet ([RowID], [Column], [Value])
SELECT [ID]
,[Column]
,[Value]
FROM
(
SELECT [ID]
,CAST([Value01] AS NVARCHAR(256))
,CAST([Value02] AS NVARCHAR(256))
,CAST([Value03] AS NVARCHAR(256))
FROM @Table01
) DS ([ID], [Value01], [Value02], [Value03])
UNPIVOT
(
[Value] FOR [Column] IN ([Value01], [Value02], [Value03])
) UNPVT
END;
ELSE
BEGIN;
INSERT INTO @ResultSet ([RowID], [Column], [Value])
SELECT [ID]
,[Column]
,[Value]
FROM
(
SELECT [ID]
,CAST([Value01] AS NVARCHAR(256))
FROM @Table02
) DS ([ID], [Value01])
UNPIVOT
(
[Value] FOR [Column] IN ([Value01])
) UNPVT
END;
SELECT *
FROM @ResultSet;
然后在报告中我需要再次执行pivot
操作。这是一种解决方法,有许多限制:
unpivot
数据强制转换为其最大类型(通常为字符串)pivot
- > unpivot
),而不仅仅是渲染数据; 和其他人..
答案 3 :(得分:0)
对于此,您可以创建一个标量值函数,该函数返回xml类型列,然后您可以将该xml标记值填充到报告屏幕
CREATE FUNCTION ReportFunc
(
@intReporttype int,
@dtStartdate datetime
)
RETURNS XML
BEGIN
Declare @xmlResult xml
If @intReporttype = '1'
SET @xmlResult = (
select lcustomerid, lname, fname
from customers
Where dtcreated > @dtStartdate
FOR XML PATH (''), TYPE
)
Else if @intReporttype = '2'
SET @xmlResult = (
Select barcode, lname, fname
from employees
where dtcreated > @dtStartdate
FOR XML PATH (''), TYPE
)
Else if @intReporttype = '3'
SET @xmlResult = (
Select thetime, lname, name, barcode, lcustomerid
from customers
where dtcreated > @dtStartdate
FOR XML PATH (''), TYPE
)
RETURN @xmlResult
END
答案 4 :(得分:0)
如果您可以使用存储过程然后为了可维护性,我会考虑使用一个调用其他存储过程的主存储过程来返回不同的结果集:
CREATE PROCEDURE MyProc_1(@startdate DateTime)
AS
BEGIN
SELECT lcustomerid, lname, fname
FROM customers WHERE dtcreated > @startdate
END
GO
CREATE PROCEDURE MyProc_2(@startdate DateTime)
AS
BEGIN
SELECT barcode, lname, fname
FROM employees where dtcreated > @startdate
END
GO
CREATE PROCEDURE MyProc_3(@startdate DateTime)
AS
BEGIN
SELECT thetime, lname, name, barcode, lcustomerid
FROM Customers WHERE dtcreated > @startdate
END
GO
CREATE PROCEDURE MyProc(@Reporttype char(1), @startdate DateTime)
AS
BEGIN
IF @Reporttype = '1' EXEC MyProc_1 @startdate
ELSE IF @Reporttype = '2' EXEC MyProc_2 @startdate
ELSE IF @reporttype = '3' EXEC MyProc_3 @startdate
END
GO
使用:
DECLARE @dt datetime = getdate()
EXEC MyProc 1, @dt
答案 5 :(得分:0)
CREATE Proc Emp_det
(
@Reporttype INT,
@startdate DATETIME
)
AS
BEGIN
If @Reporttype = '1' BEGIN
Select lcustomerid, lname, fname
FROM customers
WHERE dtcreated > @startdate
END
ELSE IF @Reporttype = '2' BEGIN
Select barcode, lname, fname
FROM employees
WHERE dtcreated > @startdate
END
ELSE IF @reporttype = '3' BEGIN
Select thetime, lname, name, barcode, lcustomerid
FROM Customers
WHERE dtcreated > @startdate
END
END
GO
Exec Emp_det 1,GETDATE()