Sql server 2008 如何在多对多映射表中高效地创建数据的逻辑子集?
我在发票和信用卡交易之间有一种多对多的关系,我试图将两者的总和映射在一起。思考这个问题的最好方法是将TransactionVoiceMap想象成一个二部图。对于每个连接的子图,查找该子图中所有发票的总数和所有交易的总数。在我的查询中,我想返回为每个子图计算的值以及它们关联的事务ID。关联交易的总额应相同 更明确地说,鉴于以下交易/发票Sql server 2008 如何在多对多映射表中高效地创建数据的逻辑子集?,sql-server-2008,tsql,many-to-many,aggregate-functions,Sql Server 2008,Tsql,Many To Many,Aggregate Functions,我在发票和信用卡交易之间有一种多对多的关系,我试图将两者的总和映射在一起。思考这个问题的最好方法是将TransactionVoiceMap想象成一个二部图。对于每个连接的子图,查找该子图中所有发票的总数和所有交易的总数。在我的查询中,我想返回为每个子图计算的值以及它们关联的事务ID。关联交易的总额应相同 更明确地说,鉴于以下交易/发票 Table: TransactionInvoiceMap TransactionID InvoiceID 1 1 2
Table: TransactionInvoiceMap
TransactionID InvoiceID
1 1
2 2
3 2
3 3
Table: Transactions
TransactionID Amount
1 $100
2 $75
3 $75
Table: Invoices
InvoiceID Amount
1 $100
2 $100
3 $50
我期望的输出是
TransactionID TotalAsscTransactions TotalAsscInvoiced
1 $100 $100
2 $150 $150
3 $150 $150
请注意,发票2和3以及交易记录2和3是逻辑组的一部分
这里有一个解决方案(简化,名称更改),显然有效,但速度非常慢。我很难弄清楚如何优化它,但我认为这将涉及到消除事务分组中的子查询。请随意提出完全不同的建议
with TransactionInvoiceGrouping as (
select
-- Need an identifier for each logical group of transactions/invoices, use
-- one of the transaction ids for this.
m.TransactionID,
m.InvoiceID,
min(m.TransactionID) over (partition by m.InvoiceID) as GroupingID
from TransactionInvoiceMap m
)
select distinct
g.TransactionID,
istat.InvoiceSum as TotalAsscInvoiced,
tstat.TransactionSum as TotalAsscTransactions
from TransactionInvoiceGrouping g
cross apply (
select sum(ii.Amount) as InvoiceSum
from (select distinct InvoiceID, GroupingID from TransactionInvoiceGrouping) ig
inner join Invoices ii on ig.InvoiceID = ii.InvoiceID
where ig.GroupingID = g.GroupingID
) as istat
cross apply (
select sum(it.Amount) as TransactionSum
from (select distinct TransactionID, GroupingID from TransactionInvoiceGrouping) ig
left join Transactions it on ig.TransactionID = it.TransactionID
where ig.GroupingID = g.GroupingID
having sum(it.Amount) > 0
) as tstat
如果我正确理解了这个问题,我认为您正在尝试为每个发票寻找最小的交易id,我使用了排名函数来做同样的事情
WITH TransactionInvoiceGrouping AS (
SELECT
-- Need an identifier for each logical group of transactions/invoices, use
-- one of the transaction ids for this.
m.TransactionID,
m.InvoiceID,
ROW_NUMBER() OVER (PARTITION BY m.InvoiceID ORDER BY m.TransactionID ) AS recno
FROM TransactionInvoiceMap m
)
SELECT
g.TransactionID,
istat.InvoiceSum AS TotalAsscInvoiced,
tstat.TransactionSum AS TotalAsscTransactions
FROM TransactionInvoiceGrouping g
CROSS APPLY(
SELECT SUM(ii.Amount) AS InvoiceSum
FROM TransactionInvoiceGrouping ig
inner JOIN Invoices ii ON ig.InvoiceID = ii.InvoiceID
WHERE ig.TransactionID = g.TransactionID
AND ig.recno = 1
) AS istat
CROSS APPLY(
SELECT sum(it.Amount) AS TransactionSum
FROM TransactionInvoiceGrouping ig
LEFT JOIN transactions it ON ig.TransactionID = it.TransactionID
WHERE ig.TransactionID = g.TransactionID
AND ig.recno = 1
HAVING SUM(it.Amount) > 0
) AS tstat
WHERE g.recno = 1
我已在以下方面实施了解决方案: 可能还有一些优化的空间(包括我的对象命名!),但我相信我至少有一个正确的解决方案,它将收集所有可能的交易发票关系,以包括在计算中 我无法在这个页面上获得现有的解决方案来提供OP所需的输出,并且随着我添加更多的测试数据,它们变得更加丑陋。我不确定OP发布的“慢”解决方案是否正确。很可能我误解了这个问题 其他信息:
我经常看到,在处理大型数据集时,递归查询可能会很慢。也许这可以成为另一个问题的主题。如果是这样的话,在SQL端尝试的事情可能是限制范围(添加
where
子句),索引基表,首先将CTE选择到临时表中,索引该临时表,为CTE考虑更好的停止条件……当然,首先要配置文件。它们被分组,因为它们都相互“接触”。如果为每个关系绘制直线,则会有一个覆盖这四个对象的图形。我以为这种分组有一个数学名称,但我记不起来了。@StuartBranhan-所以,他们分组是因为他们有一个共同的发票?这就是工作原理吗?。仅出于这个原因,您将150美元作为交易总额,因为您将交易2和交易3中的金额相加?是的,或者如果存在普通交易。图形隐喻最能解释它。我之前回复的评论是你写的吗?保留评论可能是一个好主意,这样它们最终会对以后的读者有意义。对不起,我试图编辑我的评论,但最终删除了它,我无法取消删除它。我认为您希望将此数据表示的图形划分为连接的组件,在这种情况下是相关的,我发布的查询结果也不正确。我一定是把它简化错了。有一个教训是,首先要在表变量上试用它。;)将让您知道它与您的代码是如何配合的。在玩了一些之后,您的解决方案似乎比我们目前拥有的更为正确。它仍然很慢,但我认为在前端进行一些调整和UI更改可以让它工作。稍后我将用最终解决方案更新此答案。递归CTE真的很难让你动脑。>\uu>我很高兴这让你开始了。我只是添加了一些改进的可能性。迫不及待地想看到你的最终答案,我感谢你的赏金。
;with TranGroup as (
select TransactionID
, InvoiceID as NextInvoice
, TransactionID as RelatedTransaction
, cast(TransactionID as varchar(8000)) as TransactionChain
from TransactionInvoiceMap
union all
select g.TransactionID
, m1.InvoiceID
, m.TransactionID
, g.TransactionChain + ',' + cast(m.TransactionID as varchar(11))
from TranGroup g
join TransactionInvoiceMap m on g.NextInvoice = m.InvoiceID
join TransactionInvoiceMap m1 on m.TransactionID = m1.TransactionID
where ',' + g.TransactionChain + ',' not like '%,' + cast(m.TransactionID as varchar(11)) + ',%'
)
, RelatedTrans as (
select distinct TransactionID, RelatedTransaction
from TranGroup
)
, RelatedInv as (
select distinct TransactionID, NextInvoice as RelatedInvoice
from TranGroup
)
select TransactionID
, (
select sum(Amount)
from Transactions
where TransactionID in (
select RelatedTransaction
from RelatedTrans
where TransactionID = t.TransactionID
)
) as TotalAsscTransactions
, (
select sum(Amount)
from Invoices
where InvoiceID in (
select RelatedInvoice
from RelatedInv
where TransactionID = t.TransactionID
)
) as TotalAsscInvoiced
from Transactions t