2017-01-19 29 views
8

我有一系列基於報告類型的查詢。爲簡單起見這裏是我想要做的一個例子:我運行3個獨立的查詢的基礎上,正在傳遞的報告類型具有多個查詢和不同選定列的存儲函數

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 

你會發現。您還會注意到我將返回不同的列和列數。

我想使這個存儲函數,並根據我通過的報告類型返回我需要的列。但是,我知道,因爲列的數量和列名是不同的 - 這不會像我希望的那樣用作存儲函數。

這裏的主要問題是報告這些信息 - 我不想有單獨的功能,因爲我必須爲每個報告類型維護不同的報告。

有沒有辦法讓這項工作?

+10

還不如一個用戶定義的函數,但是你可以從它創建一個存儲過程有一點問題都沒有。 –

+1

試一試'創建PROC proc_name中(@Reporttype CHAR(1)) 作爲 開始 如果@Reporttype = '1' 選擇lcustomerid,LNAME,從客戶 FNAME 凡dtcreated> @startdate 否則,如果@Reporttype = '2' 選擇條碼,LNAME,FNAME 從員工那裏 dtcreated> @startdate 否則,如果@reporttype = '3' 選擇thetime,LNAME,名稱,條形碼,lcustomerid 從客戶那裏 dtcreated> @startdate 結束' –

+1

我想你應該有3個不同的函數或者存儲過程,並控制從你的代碼執行哪一個函數,你將需要不同的方式來處理基於reporttype返回的數據。 –

回答

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()) 
0

在SQL就很難創造相似,所以一般的或抽象的東西的功能,特別是當它與柱的側向承載力SELECT做。如果您的目的是儘可能少寫代碼,以便您的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 '[email protected]+' 
from '[email protected] +' 
where dtcreated > '''+CONVERT(varchar(10), @startdate, 121)+'''' 

EXEC(@sSQL) 
END 

你會想要你需要的情況下,只添加另一條新的報表類型每次調用它

EXEC MyProcedure 1,'20170131' 

例如 有了這個代碼與請求的列名稱。我在使用Crystal Reports用這樣的方式,我認爲這是最好的解決方案

+0

可能有一些語法錯誤,我沒有測試,但你可以看到我的觀點 – jambonick

+0

你的查詢只適用於一個表,但應該也適用於employees表。有問題的評論SP已經提供,沒有動態查詢。 –

+1

你是對的,我沒有看到表名的變化,我編輯了答案。事實上,SP可以在沒有動態SQL的情況下工作,但在這種情況下,SELECT語句應該被重寫。我的目的是創建一個儘可能少代碼重複的腳本 – jambonick

0

如果您不能使用存儲過程,你需要使用的功能,你可以UNPIVOT數據和比client side可以PIVOT它。

當不同數量的列返回到SQL Server Reporting Services報告時,我需要做這樣的事情。例如,下面的代碼總是返回三列 - RowIDColumnValue

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),而不是僅僅渲染數據;
  • 並不大數據量的運作良好(它是緩慢的)

等..

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 
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 
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() 
相關問題