2010-07-07 30 views
1

我有一個複雜的SQL查詢,需要進一步過濾。 WHERE子句中的部分看起來像這樣:如何獲取SQL函數以返回WHERE子句中IN語句要使用的列表?

Where P.PeriodID in (36, 37) 

我需要得到它看起來更像是這樣的:

Where P.PeriodID in dbo.GetPeriodsInRange(@startDate, @endDate) 

函數必須返回到由IN語句中使用PeriodIDs列表。我真的很喜歡寫功能,所以我需要一些幫助。另外,我不確定如何處理邊緣案例,比如說在指定的日期範圍內沒有時段。

上面的函數不需要爲每一行進行評估。每行都是一樣的,所以可能會有一些優化可以完成,也許在執行查詢之前。

我很確定我在這裏打破了幾個「最佳實踐」,所以如果有更好的方法來做到這一點,請給我指出。但是,性能不是問題,所以我願意爲了簡單而犧牲性能。

我的問題適用於T-SQL(MS SQL服務器2000/2005)

+0

如何:WHERE P.PeriodID IN(SELECT ID FROM dbo.GetPeriodsInRange(@startDate,@EndDate)) – 2010-07-07 09:49:35

回答

2

我的解決方案是創建一個功能木瀆建議。我使用this

從鏈接:

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
CREATE FUNCTION [dbo].[ufn_GenerateIntegers] (@MinValue INT, @MaxValue INT) 
RETURNS @Integers TABLE ([IntValue] INT) 
AS 
BEGIN 
    WHILE @MinValue <= @MaxValue 
    BEGIN 
     INSERT INTO @Integers ([IntValue]) VALUES (@MinValue) 
     SET @MinValue = @MinValue + 1 
    END 

    RETURN 
END 
GO 

之後,我使用一個內部聯接是這樣的:

use tempdb 

select *into #test from 
(
    select 1 as n, 35 as periodId 
    union 
    select 2 as n, 36 as periodId 
    union 
    select 1 as n, 36 as periodId 
    union 
    select 2 as n, 37 as periodId 
) a 

select p.* from #test p 
inner join [dbo].[ufn_GenerateIntegers](36, 37) on [IntValue] = periodId 

您可以生成一個字符串,然後執行它,但它不是很在這裏建議,我認爲。

+0

聽起來很有希望,但SQL Server 2000支持表值函數?我正在開發SQL 2005,但部署將在SQL 2000上進行。 – 2010-07-07 10:34:26

+0

這很適合於SQL 2005.任何想法如果它能在SQL 2000上工作?順便說一句 - 你的內連接的語法不適合我,我不得不改變它一點。 – 2010-07-07 10:59:36

+0

我認爲它可能在2000 http://www.sqlteam.com/article/user-defined-functions但我無法測試它。 – DomreiRoam 2010-07-07 11:11:11

1

好吧,如果getPeriodsInRange實際上只是一個SQL查詢,你可以只使用,而不是過程的嵌套查詢(你說的簡單! ):

Where P.PeriodID in (Select PeriodID from MyDateTable WHERE pd > SomeMinValue AND pd < SomeMaxValue) 
0

無論你是在GetPeriodsInRange功能做 - 不能你剛纔拉那到主查詢像...

Where P.PeriodID in 
(
select PeriodID from...etc 
) 

這不會工作,如果函數做更復雜的東西!也許你可以讓我們看看函數中有什麼?

1

我會寫一個表值函數,它返回一個包含您的期間的單列表。然後你可以內部連接這個表值結果。這樣它應該只執行一次,而不是每一行(但我不完全確定這一點)。

延伸閱讀: Table-Valued User-Defined Functions (MSDN)

乾杯 馬蒂亞斯

+0

如果SQL服務器是什麼好,內部查詢將無論如何優化掉。 – Borealid 2010-07-07 09:52:12

+0

Matthias - SQL Server 2000是否支持表值函數?我正在開發SQL 2005,但部署將在SQL 2000上進行。這是我認爲會起作用的。 – 2010-07-07 10:35:25

+0

根據下面的代碼項目文章它確實。但是當我寫下我的答案時,我沒有想到子查詢 - 我認爲這可能會更簡單... http://www.codeproject.com/KB/database/TableValuedFnsAsArrays.aspx – 2010-07-07 11:58:55

1

首先,你不是「思考套路」。 SQL語言只有一個數據結構,即表格,即行列。列的數據類型必須是標量以滿足第一範式。所以沒有數組,列表等

儘管您可能會生成PeriodID值的列表,然後將列表噴入SQL查詢的文本中,然後使用動態SQL功能執行它,但這不是一種可行的方法。

考慮您的

Where P.PeriodID in (36, 37) 

...可以改寫爲

Where P.PeriodID IN (
        SELECT 36 
        UNION ALL 
        SELECT 37 
        ) 

...甚至

WHERE EXISTS (
       SELECT * 
       FROM (
         SELECT 36 
         UNION ALL 
         SELECT 37 
        ) AS DT1 (PeriodID) 
       WHERE P.PeriodID = DT1.PeriodID 
      ); 

,而且你會希望越來越想法使用表而不是標識符列表。

這就是說,退後一步,這看起來像一個情況,你最好使用自然鍵的週期工作,即化合物(StartDate, EndDate),而不是人工/代理鍵PeriodID。僅使用日期就意味着您只需找到重疊的例如

SELECT P1.PeriodID 
    FROM Periods AS P1 
WHERE CASE 
      WHEN @StartDate > P1.StartDate THEN @StartDate 
      ELSE P1.StartDate 
     END 
     <= 
     CASE 
      WHEN @EndDate > P1.EndDate THEN P1.EndDate 
      ELSE @EndDate 
     END; 
+0

你說得對 - 我沒有在想什麼 - 我在考慮更多的程序,並首先在紙上使用僞程序代碼設計解決方案。我的SQL技能非常薄弱,我更多的是C#開發人員。感謝您提供豐富的解釋 - 我已經學會了很多! – 2010-07-07 11:23:01

相關問題