2009-09-24 29 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不会落在开始和结束之间,在处理付款时也不会有空的结束日期行。 –

相关问题