我有一个复杂的查询,在select中有很多列,还有很多连接。 2个主要表(不是唯一的表)是SalesDocumentItems和Transactions。我只想要具有唯一SalesDocumentItemIDs的记录,并且我愿意通过仅使用MAX(TransactionDate)连接匹配的Transactions记录来实现此目的。这是一个例子:
select *
from @Financials f1
where f1.TransactionDate = (
select MAX(TransactionDate)
from @Financials
where SalesDocumentItemID = f1.SalesDocumentItemID
)
该查询实际上完美无缺,完全符合我的需要,但在UDF中填充@Financials已证明不可能实现。事实上,我有另一个关于该主题的堆栈问题:
How to return a table variable from a function (UDF)?
无论其他问题的结果如何,我仍然想知道如何在不借助表变量的情况下做到这一点。我也认为GROUP BY不是一个好的选择,因为在选择和大量的连接中有很多列,并且它看起来太毛茸茸而不能走这条路。
**以下编辑**
我包括我原来的选择声明。我真的需要一点帮助,如何将你们已经显示的方法集成到我当前的查询中。不知道如何连接这两个。非常感谢。
Select [a bunch of columns, including SalesDocumentItemID and TransactionDate]
From
( Select [a bunch of Transaction columns]
From Transactions trx_detail
Where trx_detail.TransactionStatusID = 1
and trx_detail.TransactionDate >= @StartDate
and trx_detail.TransactionDate < DATEADD(dd,1,@EndDate)
) t
inner join gym.Account acct on t.AccountID = acct.AccountID
inner join gym.SalesDocumentItemTransaction linker on linker.TransactionId = t.TransactionID --do not need to aggregate because there is only ever one set of sales docs items when looking from the transaction's perspective
inner join gym.SalesDocumentItems docitems on linker.SalesDocumentItemID = docitems.SalesDocumentItemID
inner join gym.Product prod on docitems.ProductID = prod.ProductID
left join gym.ProductGroup pgroup on prod.ProductGroupID = pgroup.ProductGroupID
left join gym.RevenueGroup rgroup on pgroup.RevenueGroupID = rgroup.RevenueGroupID
left join gym.[Site] home on acct.SiteID = home.SiteID
left join gym.[Person] collector on t.CollectorPersonID = collector.PersonID
left join gym.[Registration] reg on reg.RegistrationID = t.RegistrationID
left join gym.[Site] trx_site on trx_site.SiteID = reg.SiteID
left join gym.TransactionStatus tstatus on t.TransactionStatusID = tstatus.TransactionStatusID
Where (@SiteID = 0 OR (@SiteID <> 0 and docitems.RevenueSiteID = @SiteID))
数据示例:
SalesDocumentID TransactionDate
1020557 2014-06-25 16:44:01.930
1020557 2014-06-25 16:44:17.557
1020557 2014-06-25 16:44:33.210
1020558 2014-06-25 16:44:50.007
1020558 2014-06-25 16:44:33.210
1020559 2014-06-25 16:44:50.007
这是我最终的非编译查询,基于Blam的建议:
select tjoin.*
from (
Select t.SalesDocumentItemID, t.TransactionDate, SeqNum=row_number()
over (partition by t.SalesDocumentItemID
order by t2.TransactionDate desc)
From
( --Filter Transactions First for optimization purposes, prior to joining to the linker table
Select
--Transaction Information
t.TransactionID
,t.AccountID
,t.AccountContractID
,t.SalesDocumentID
,docitems.SalesDocumentItemID
,t.CollectorPersonID
,trx_site.SiteID as CollectedSiteID
,t.SalesPersonID
,t.PaymentMethodID
,t.CCnumber
,t.TransactionStatusID
,t.TransactionDate
,t.TransactionAmount
,t.APIResponseCode
,t.APIResponseReason
,t.RegistrationID
,t.TransactionTypeID
,year(t.TransactionDate) as TransactionYear
,month(t.TransactionDate) as TransactionMonth
,datepart(ww, t.TransactionDate) as TransactionWeek
,day(t.TransactionDate) as TransactionDay
--Trx Type Breakdown TransactionTypeID Name; 1 BillingProcess; 2 POS; 3 PaymentOnAccount; 4 Refund
,case when t.TransactionTypeID = 1 then linker.Amount else 0 end as BillingProcess
,case when t.TransactionTypeID = 2 then linker.Amount else 0 end as PointOfSale
,case when t.TransactionTypeID = 3 then linker.Amount else 0 end as PaymentOnAccount
,case when t.TransactionTypeID = 4 then linker.Amount else 0 end as Refund
,linker.Amount as LineItemAmount
--Product Information
,docitems.ProductID
,docitems.Amount
,docitems.Quantity
,docitems.TaxAmount
,docitems.TotalAmount
,docitems.AmountPaid
,docitems.RevenueSiteID
,prod.ProductName
,prod.ProductGroupID
,pgroup.ProductGroup
,pgroup.RevenueGroupID --added for new available field 17 May 2014
,rgroup.RevenueGroup
--Account Info (Home Site for non-inventoried products filter - read: repetitives)
,acct.IsActive
,acct.SiteID
,home.SiteName
--Collector Info
,gym.Person__FormatName(collector.FirstName, collector.LastName, collector.MiddleName, collector.NickName) as CollectorName
--Collected Site Info (Sale Site for inventoried products filter - read: merchandise)
,trx_site.SiteName as CollectedSiteName
--Transaction Status Info
,tstatus.Name as TransactionStatus
From
( --Filter Transactions First for optimization purposes, prior to joining to the linker table
Select
trx_detail.TransactionID
,trx_detail.AccountID
,trx_detail.AccountContractID
,trx_detail.SalesDocumentID
,trx_detail.CollectorPersonID
,trx_detail.SalesPersonID
,trx_detail.PaymentMethodID
,trx_detail.TransactionStatusID
,trx_detail.TransactionDate
,trx_detail.TransactionAmount
,trx_detail.APIResponseCode
,trx_detail.APIResponseReason
,trx_detail.TransactionTypeID
,trx_detail.RegistrationID
,trx_detail.CCNumber
From
gym.[Transaction] trx_detail
Where
trx_detail.TransactionStatusID = 1 --successful transactions only
and trx_detail.TransactionDate >= @StartDate
and trx_detail.TransactionDate < DATEADD(dd,1,@EndDate) --need to add 1 day to account for the Time portion of the TransactionDate. Notice it is simply Less Than (no equal).
) t
inner join gym.Account acct on t.AccountID = acct.AccountID
inner join gym.SalesDocumentItemTransaction linker on linker.TransactionId = t.TransactionID --do not need to aggregate because there is only ever one set of sales docs items when looking from the transaction's perspective
inner join gym.SalesDocumentItems docitems on linker.SalesDocumentItemID = docitems.SalesDocumentItemID
inner join gym.Product prod on docitems.ProductID = prod.ProductID
left join gym.ProductGroup pgroup on prod.ProductGroupID = pgroup.ProductGroupID
left join gym.RevenueGroup rgroup on pgroup.RevenueGroupID = rgroup.RevenueGroupID
left join gym.[Site] home on acct.SiteID = home.SiteID
left join gym.[Person] collector on t.CollectorPersonID = collector.PersonID
left join gym.[Registration] reg on reg.RegistrationID = t.RegistrationID
left join gym.[Site] trx_site on trx_site.SiteID = reg.SiteID
left join gym.TransactionStatus tstatus on t.TransactionStatusID = tstatus.TransactionStatusID
Where (@SiteID = 0 OR (@SiteID <> 0 and docitems.RevenueSiteID = @SiteID))) tjoin
where tjoin.SeqNum = 1
答案 0 :(得分:2)
GROUP BY并不是一件坏事!在这种情况下,窗口函数可能是更好的选择。这将从每个SalesDocumentItemID的交易中获得1条记录:
select t.*
from (
select t2.*, SeqNum=row_number() over (partition by SalesDocumentItemID order by SomeSensibleField)
from Transactions t2
) t
where SeqNum = 1
注意与row_number()函数一起使用的ORDER BY。您需要指定如何为每个SalesDocumentItemID选择所需的记录。例如。如果你想要最新的,你可以使用&#34;(按SalesDocumentID分区按SomeDateColumn desc 排序)&#34;或任何适合您需要的东西。
更仔细地检查窗口函数。它们非常强大。
答案 1 :(得分:1)
至于退回一张桌子 How do I "Declare the scalar variable" in a VIEW in Sql Server (2005)
为什么你觉得你需要一个表变量?
我假设这两个表是SalesDocumentItems和Transactions
select tjoin.*
from ( select *, SeqNum=row_number() over (partition by t1.SalesDocumentItemID
order by t2.TransactionDate desc)
from SalesDocumentItems t1
join Transactions t2
on t1.SalesDocumentItemID = t2.SalesDocumentItemID
) tjoin
where tjoin.SeqNum = 1
如果SalesDocumentItems确实是一个复杂的查询,那么只需使用cte
WITH SalesDocumentItems (SalesDocumentItemID, TransactionDate, ...)
AS
(
SELECT ...
)
select tjoin.*
from ( select *, SeqNum=row_number() over (partition by t1.SalesDocumentItemID
order by t2.TransactionDate desc)
from SalesDocumentItems t1
join Transactions t2
on t1.SalesDocumentItemID = t2.SalesDocumentItemID
) tjoin
where tjoin.SeqNum = 1
你这样做比你需要的更难
select tjoin.*
from (
Select t.SalesDocumentItemID, tTransactionDate
, SeqNum=row_number() over (partition by t.SalesDocumentItemID
order by t2.TransactionDate desc)
From Transactions t
inner join gym.Account acct
on t.AccountID = acct.AccountID
and t.TransactionStatusID = 1
and t.TransactionDate >= @StartDate
and t.TransactionDate < DATEADD(dd,1,@EndDate)
inner join gym.SalesDocumentItemTransaction linker
on linker.TransactionId = t.TransactionID
inner join gym.SalesDocumentItems docitems
on linker.SalesDocumentItemID = docitems.SalesDocumentItemID
inner join gym.Product prod
on docitems.ProductID = prod.ProductID
and (@SiteID = 0 OR docitems.RevenueSiteID = @SiteID)
left ..... does note effect the core question
inner join Transactions t2
on t1.SalesDocumentItemID = t2.SalesDocumentItemID ) tjoin
where tjoin.SeqNum = 1