Sql 仅匹配存在多行的联接中的一个特定行

Sql 仅匹配存在多行的联接中的一个特定行,sql,advantage-database-server,Sql,Advantage Database Server,(Advantage Database Server)我有一个服务提供商表,出于审计目的,这些服务提供商从不被删除。它们有开始日期和结束日期;在发生名称或地址等更改的情况下,现有行的日期为结束日期,创建新行,并为更改的数据指定新的开始日期 在处理向这些提供商付款的过程中,我需要一个摘要页面,其中列出提供商名称、地址、标识符(ProvID)和支付的总金额。这是在一个相当简单的查询中使用SUM()和groupby完成的 当指定的提供程序标识符有两行或多行时,就会出现问题。我最终得到了重复的行(如果没

(Advantage Database Server)我有一个服务提供商表,出于审计目的,这些服务提供商从不被删除。它们有开始日期和结束日期;在发生名称或地址等更改的情况下,现有行的日期为结束日期,创建新行,并为更改的数据指定新的开始日期

在处理向这些提供商付款的过程中,我需要一个摘要页面,其中列出提供商名称、地址、标识符(ProvID)和支付的总金额。这是在一个相当简单的查询中使用SUM()和groupby完成的

当指定的提供程序标识符有两行或多行时,就会出现问题。我最终得到了重复的行(如果没有抓到,可能会导致向该提供商支付多笔款项)

我的第一个想法是使用一些东西(丑陋,但表现相当快),比如子选择:

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)

我在其他情况下(例如,查找在特定日期提供的服务的适当提供者)使用

不幸的是,由于问题查询是带有聚合的GROUP BY,因此服务日期不可用

有什么建议吗


编辑:我要查找的是EndDate为空的行(如果存在),或者是Max(EndDate)为空的行(如果不存在)。这涵盖了这样的情况,例如,一个供应商昨天被终止,但上周确实工作了,我们将在下周向他们付款。

也许可以使用子查询代替第二个表:

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

这是假设如果没有max-enddate,您将返回NULL。

您所指的是数据仓库的类型2维度

您必须通过ID、开始日期和结束日期加入,才能获得正确的数据

奥托姆码

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

在第二种情况下,只有在没有NULL EndDate的情况下,才能获得最大值

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

所以我猜,如果有一行的结束日期为空,那么您需要该行,否则您需要具有最大结束日期的行

我不确定是否有广告,但以下内容可以在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)
)

运算符返回第一个非空参数,因此这基本上只是将空值设置为将来的某个时间,这样,如果存在空结束日期,SELECT MAX将为您提供一个空结束日期。

您的提供者表中有什么表示当前日期?EndDate=NULL、EndDate=Max(EndDate)或EndDate='9999-01-01'?这三个选项都是有效的,但这应该是明确无误的,因为如果不是这样,那么无论您如何巧妙地构建这个特定的查询,查询中都会出现重复的行。所以我建议在provider表中解决这个问题,然后类似这样的方法应该可以工作:

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

无法修复提供程序表。这是历史数据和当前数据,审计人员不允许我们出于任何原因更改这些数据。如果重组数据是一种选择,我就不需要在这里发帖了。不过,谢谢。再仔细想想,你确实有一个明确的条件。你想寄到现在的地址,对吗?那么你就不需要s.ServiceDate了。只需使用“其中p.EndDate为null或(p.StartDate和p.EndDate之间的sysdate)”。这有帮助吗?不幸的是,没有。请参阅我对原始帖子的编辑,内容是关于终止服务的提供商在期限日期之前提供了未完成的服务,但在期限日期之后支付。SysDate不会介于开始和结束之间,在处理付款时也不会有空的结束日期行。正如我提到的,我不能这样做,因为我使用的是聚合函数和分组依据。由于聚合,交易日期不可用。抱歉。我显然掩饰了那部分,没问题。谢谢你的尝试,Raj。我接受这个答案是因为它非常圆滑,而且比najmeddine的“不存在”答案稍微快一点(但只是因为索引选择很好)。谢谢,基普。:-)刚刚合并到我的代码库中,并根据实际数据进行了测试。100%有效,无明显性能损失。再次感谢你,基普!注意:对于其他ADS用户:COALESCE()调用需要添加一项:将它们都更改为COALESCE(EndDate,CAST('2037-01-01'作为SQL_DATE)),因为ADS不会像其他数据库那样自动从日期文本进行转换。@Ken White:如果有多行的结束日期为NULL,则会得到多行。不过,我想在您的模式中,这会被视为损坏的数据。@najmeddine:我接受Kip的回答,因为它比您的回答快一点(因为他使用了两个COALESCE()函数调用,而不是为NOT EXISTS测试添加另一个子选择)。不过,你的也很好,所以我也投了更高的票。谢谢
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