2009-09-24 31 views
2

(Advantage數據庫服務器)我有一個服務提供程序的表,爲了審計的目的,從不刪除。他們有一個開始日期和結束日期;在名稱或地址等更改的情況下,現有的行將結束日期,創建新行,併爲已更改的數據分配新的開始日期。匹配存在多個JOIN的只有一個特定的行

在處理向這些提供商付款的過程中,我需要一個彙總頁面,其中列出了提供商名稱,地址,標識符(ProvID)以及支付的總金額。這是通過一個SUM()和GROUP BY的相當直接的查詢完成的。

當指定提供程序標識符有兩行或更多行時,會出現此問題。我最終得到重複的行(如果沒有被捕獲,可能會導致對該提供者的多次付款)。

我首先想到的是使用的東西(難看,但表現相當快)就像一個子查詢:

SELECT ... FROM service s 
INNER JOIN provider p ON p.ProvID = s.ProvID 
AND (p.EndDate IS NULL or p.EndDate = (SELECT Max(EndDate) FROM 
    provider lu WHERE lu.ProvID = s.ProvID)) 

不幸的是,這仍然最終找到兩行;一行爲NULL EndDate,另一行爲MAX(EndDate)。

我處理這個問題在其他情況下(如,定位爲提供在特定日期服務的正確ProvID)使用

p.EndDate is null or (s.ServiceDate BETWEEN p.StartDate AND p.EndDate) 

不幸的是,因爲這個問題的查詢是一組由一個總的服務日期不可用。

有什麼建議嗎?

編輯:我正在尋找的是要麼是NULL EndDate行,如果它存在,或者與最大(EndDate)行如果NULL行不存在。例如,在這種情況下,供應商昨天被終止,但上週做了工作,我們將在下週支付。

回答

3

所以我想,如果有一個與NULL結束日期的行,你想要那個,否則你想要一個結束日期最長的那個?

我不知道關於ADS,但下面將SQL Server上運行:

SELECT ... FROM service s 
INNER JOIN provider p ON p.ProvID = s.ProvID 
AND (COALESCE(p.EndDate, '2037-01-01') = (
    SELECT Max(COALESCE(EndDate, '2037-01-01')) FROM 
    provider lu WHERE lu.ProvID = s.ProvID) 
) 

COALESCE操作返回第一個非空參數,所以這基本上是空值設置爲一個時間在將來,這樣SELECT MAX將會給你一個空結束日期,如果有的話。

+0

我接受這個答案,因爲它非常漂亮,它比najmeddine的NOT EXISTS回答稍微快一些(但由於索引選擇良好,所以答案略有些微)。謝謝,基普。 :-) –

+0

剛剛合併到我的代碼庫並根據實際數據進行測試。工程100%,沒有顯着的性能損失。再次感謝,基普!其他ADS用戶的注意事項:COALESCE()調用需要添加一項:將它們都更改爲COALESCE(EndDate,CAST('2037-01-01'AS SQL_DATE)),因爲ADS不會自動從日期進行轉換文字像其他數據庫一樣。 –

+0

@Ken White:如果你有多於一行的NULL結束日期,你會得到多於一行的結果。我想這將被視爲您的架構中的損壞數據。 – Kip

0

,取代第二臺也許使用子查詢:

SELECT ... FROM service s 
INNER JOIN (SELECT ..., Max(EndDate) FROM 
    provider lu WHERE lu.ProvID = s.ProvID GROUP BY ...) p ON p.ProvID = s.ProvID 

這是假設你會得到空回來,如果沒有最大結束日期。

0

你所指的是數據倉庫的第二維。

您必須加入ID StartDate和EndDate以獲取正確的數據。

OTTOMH在第二個條件碼

SELECT TransactionId, TransactionType 
FROM TransactionList Tx 
    INNER JOIN TransactionType TxType 
     ON Tx.TransactionTypeId = TxType.TxTypeId 
     AND Tx.TransactionDate Between TxType.StartDate and TxType.EndDate 
+0

正如我所說,我不能這樣做,因爲我使用的聚合函數和GROUP BY。由於彙總,交易日期不可用。 –

+0

道歉。我顯然掩蓋了那部分。 –

+0

沒問題。謝謝你的試用,拉傑。 –

3

,你必須得到最高只有當不存在NULL結束日期

SELECT ... FROM service s 
INNER JOIN provider p ON p.ProvID = s.ProvID 
AND ( p.EndDate IS NULL 
    or (p.EndDate = (SELECT Max(EndDate) 
         FROM provider lu 
         WHERE lu.ProvID = s.ProvID) 
     AND NOT EXISTS (SELECT NULL 
          FROM provider lu 
          WHERE lu.ProvID = s.ProvID 
          AND lu.EndDate IS NULL) 
     ) 
    ) 
+0

@najmeddine:我接受了Kip的答案,因爲它比你的**稍微快一點(因爲他使用了兩次COALESCE()函數調用,而不是爲NOT EXISTS測試添加另一個子查詢)。不過,你的工作也很好,所以我也贊同它。謝謝! –

0

什麼在您的提供商表格中表示當前日期? EndDate = NULL,EndDate = Max(EndDate)或EndDate ='9999-01-01'?所有這三個都是有效的選擇,但這應該是明確的,因爲如果不是這樣,那麼無論您多麼巧妙地製作這個特定的查詢,最終都會在查詢中出現重複的行。所以我建議固定,在供應商表,然後這樣的事情應該工作:

select p.name, p.address, p.id, sum(s.amount) 
    from provider p 
    join service s on p.id=s.provider_id 
where p.endDate is NULL 
group by p.name, p.address, p.id 
+0

無法修復提供程序表。這既是歷史的,也是現在的數據,審計師不會允許我們無論出於何種原因改變這一點。如果重組數據是一種選擇,我不需要在這裏發佈。謝謝,不過。 –

+0

再想一想,你會有一個明確的條件。你想運送到_current_地址,對嗎?那麼你不需要s.ServiceDate。只需使用「where p.EndDate爲null或(p.StartDate和p.EndDate之間的sysdate)」。這有幫助嗎? – wallenborn

+0

不幸的是,沒有。在期限日期之前,查看我對原始帖子的編輯,瞭解關於已終止的提供者的優秀服務,但在期限日期之後支付。 SysDate不會落在開始和結束之間,在處理付款時也不會有空的結束日期行。 –

相關問題