2011-07-21 34 views
1

は、私は次のSQLパラメータ化CTEのクエリ

select * 
from  (
       select * 
       from  callTableFunction(@paramPrev) 
       .....< a whole load of other joins, wheres , etc >........ 
      ) prevValues 
      full join 
      (
       select * 
       from callTableFunction(@paramCurr) 
       .....< a whole load of other joins, wheres , etc >........ 
      ) currValues    on prevValues.Field1 = currValues.Field1 
      ....<other joins with the same subselect as the above two with different parameters passed in 
where  ........ 
group by .... 

次副選択は、クエリバー内のすべての副問い合わせの表関数に@paramに共通するようなクエリを持っています。

 select * 
     from callTableFunction(@param) 
      .....< a whole load of other joins, wheres , etc >........ 

私は関数にこれを変換し、関数を呼び出すための一つの選択肢があるが、私はかなり頻繁に 副選択クエリを変更することができる.....または場合、私は疑問に思って、私はこのようにいけません

with sometable(@param1) as 
(
     select * 
     from callTableFunction(@param) 
       .....< a whole load of other joins, wheres , etc >........ 
) 
select  
     sometable(@paramPrev)  prevValues 
     full join sometable(@currPrev) currValues on prevValues.Field1 = currValues.Field1 
where  ........ 
group by .... 

のようなCTE を使用して代替がこのまたは私はこのように使用することができる技術のような任意の構文がありますがあります。

これはSQL Server 2008 R2のものです

ありがとうございます。

答えて

2

構文をサポートしていません - このようにCTEをパラメータ化することはできません。

オンライン書籍 - http://msdn.microsoft.com/en-us/library/ms175972.aspxを参照してください。

(カッコ内の値は、CTE名の後に、出力列名のオプションのリストです)

のみ2つのパラメータ値(paramPrevcurrPrev)がある場合は、あなたがにコードを少し楽にすることができるかもしれません2つのCTEにそれらを分割することで読み - このような何か:

with prevCTE as (
      select * 
      from callTableFunction(@paramPrev) 
        .....< a whole load of other joins, wheres , etc 
........) 
,curCTE as (
      select * 
      from callTableFunction(@currPrev) 
        .....< a whole load of other joins, wheres , etc 
........), 
select  
      prevCTE  prevValues 
      full join curCTE currValues on 
prevValues.Field1 = currValues.Field1 where 
........ group by 
.... 
+0

をまず、何も解決しませんでした。副選択をCTEセクションに移動するだけで、まだコードが重複しています。私がしようとしているのは、(テーブル関数呼び出しで)共通の副選択を使用してクエリ全体を減らすことです。したがって、副選択のロジックを変更したい場合は、1か所で行います。私が今考えることのできる最良の方法は、関数にラップすることですが、私はこのメソッドが気に入らないのです。 – ManiP

1

あなたはとしてパラメータインラインテーブル値関数をサブクエリをラップして、OUTERでそれらを使用することができるはずのJOIN:

CREATE FUNCTION wrapped_subquery(@param int) -- assuming it's an int type, change if necessary... 
RETURNS TABLE 
RETURN 
    SELECT * FROM callTableFunction(@param) 
    .....< a whole load of other joins, wheres , etc ........ 
GO 

SELECT * 
FROM 
    wrapped_subquery(@paramPrev) prevValues 
     FULL OUTER JOIN wrapped_subquery(@currPrev) currValues ON prevValues.Field1 = currValues.Field1 
WHERE  ........ 
GROUP BY .... 
+0

私の場合、CREATE FUNCTIONを使用するために必要な権限レベルはありません。それでも最善の解決策が何であるか不思議です。 –

1

私の例と、あなたの後続のONステートメントがどのように公式化されるかに応じて、いくつかの違いがあるかもしれません。あなたが指定しなかったので、後続のすべての結合が最初のテーブルに対して行われたと仮定しました。 私の例では、@ prev、@ currentではなくリテラルを使用しましたが、あなたが望むものを達成するためにリテラルの代わりに変数を簡単に置き換えることができます。あなたが何をしたいか

-- Standin function for your table function to create working example. 
CREATE FUNCTION TestMe(
    @parm int) 
RETURNS TABLE 
AS 
RETURN 
    (SELECT @parm AS N, 'a' AS V UNION ALL 
    SELECT @parm + 1, 'b'  UNION ALL 
    SELECT @parm + 2, 'c'  UNION ALL 
    SELECT @parm + 2, 'd'  UNION ALL 
    SELECT @parm + 3, 'e'); 
go   
-- This calls TestMe first with 2 then 4 then 6... (what you don't want) 
-- Compare these results with those below 
SELECT t1.N AS AN, t1.V as AV, 
     t2.N AS BN, t2.V as BV, 
     t3.N AS CN, t3.V as CV 
    FROM TestMe(2)AS t1 
    FULL JOIN TestMe(4)AS t2 ON t1.N = t2.N 
    FULL JOIN TestMe(6)AS t3 ON t1.N = t3.N; 

-- Put your @vars in place of 2,4,6 adding select statements as needed 
WITH params 
    AS (SELECT 2 AS p UNION ALL 
     SELECT 4 AS p UNION ALL 
     SELECT 6 AS p) 
    -- This CTE encapsulates the call to TestMe (and any other joins) 
    ,AllData 
    AS (SELECT * 
      FROM params AS p 
      OUTER APPLY TestMe(p.p)) -- See! only coded once 
      -- Add any other necessary joins here 

    -- Select needs to deal with all the columns with identical names 
    SELECT d1.N AS AN, d1.V as AV, 
      d2.N AS BN, d2.V as BV, 
      d3.N AS CN, d3.V as CV 
     -- d1 gets limited to values where p = 2 in the where clause below 
     FROM AllData AS d1 
     -- Outer joins require the ANDs to restrict row multiplication 
     FULL JOIN AllData AS d2 ON d1.N = d2.N 
          AND d1.p = 2 AND d2.p = 4 
     FULL JOIN AllData AS d3 ON d1.N = d3.N 
          AND d1.p = 2 AND d2.p = 4 AND d3.p = 6 
     -- Since AllData actually contains all the rows we must limit the results 
     WHERE(d1.p = 2 OR d1.p IS NULL) 
     AND (d2.p = 4 OR d2.p IS NULL) 
     AND (d3.p = 6 OR d3.p IS NULL); 

は、ピボットに似ているので、必要なクエリの複雑さは、ピボット文を使用せずに、ピボット結果を作成することに似ています。
Pivotを使用していた場合、重複した行(この例に含まれているような)がアグリゲーションされます。これは、集約が望ましくないピボットを行うためのソリューションでもあります。

0

with前に、スカラ変数を割り当てるために失敗した後、私は最終的には、ストアドプロシージャや一時テーブルを使用して作業溶液を得た:

create proc hours_absent(@wid nvarchar(30), @start date, @end date) 
as 
with T1 as(
    select c from t 
), 
T2 as(
    select c from T1 
) 
select c from T2 
order by 1, 2 
OPTION(MAXRECURSION 365) 

ストアドプロシージャの呼び出し:これは何私である

if object_id('tempdb..#t') is not null drop table #t 

create table #t([month] date, hours float) 
insert into #t exec hours_absent '9001', '2014-01-01', '2015-01-01' 

select * from #t