gor*_*igh 5 sql sql-server-2008
好的,我想我一定是对SQL查询有些误解.这是一个非常罗嗦的问题,所以感谢花时间阅读它(我的问题在最后,其他一切都只是上下文).
我正在编写一个以复式本金为主的会计系统 - 货币总是在账户之间移动,交易是2 TransactionParts行或更多行减少一个账户并递增另一个账户.
某些TransactionParts行可能被标记为与税收相关,因此系统可以生成增值税销售/购买总额的报告等,因此单个交易可能有两个TransactionParts引用相同的帐户 - 一个增值税相关,另一个不相关.为了简化向用户的呈现,我有一个视图,可以为同一个帐户和事务组合多个行:
create view Accounting.CondensedEntryView as
select p.[Transaction], p.Account, sum(p.Amount) as Amount
from Accounting.TransactionParts p
group by p.[Transaction], p.Account
Run Code Online (Sandbox Code Playgroud)
然后,我有一个计算运行平衡列的视图,如下所示:
create view Accounting.TransactionBalanceView as
with cte as
(
select ROW_NUMBER() over (order by t.[Date]) AS RowNumber,
t.ID as [Transaction], p.Amount, p.Account
from Accounting.Transactions t
inner join Accounting.CondensedEntryView p on p.[Transaction]=t.ID
)
select b.RowNumber, b.[Transaction], a.Account,
coalesce(sum(a.Amount), 0) as Balance
from cte a, cte b
where a.RowNumber <= b.RowNumber AND a.Account=b.Account
group by b.RowNumber, b.[Transaction], a.Account
Run Code Online (Sandbox Code Playgroud)
由于我还没有解决的原因,某个交易(ID = 30)没有出现在用户的账户对账单上.我通过跑步证实了这一点
select * from Accounting.TransactionBalanceView where [Transaction]=30
Run Code Online (Sandbox Code Playgroud)
这给了我以下结果:
RowNumber Transaction Account Balance
-------------------- ----------- ------- ---------------------
72 30 23 143.80
Run Code Online (Sandbox Code Playgroud)
正如我之前所说,TransactionParts每个交易应该至少有两个,所以其中一个没有出现在我看来.我假设我编写视图的方式一定存在问题,并运行查询以查看是否还有其他缺失:
select [Transaction], count(*)
from Accounting.TransactionBalanceView
group by [Transaction]
having count(*) < 2
Run Code Online (Sandbox Code Playgroud)
此查询不返回任何结果 - 甚至不包括事务30!想我必须是个白痴我运行以下查询:
select [Transaction]
from Accounting.TransactionBalanceView
where [Transaction]=30
Run Code Online (Sandbox Code Playgroud)
它返回两行!因此select *只返回一行并select [Transaction]返回两者.在经历了最后两次查询并且重新运行后,我得出结论,我并不知道发生了什么.有任何想法吗?
非常感谢,如果你这么坚持我!
以下是执行计划:
每个1000行,因此找到了其他地方托管.
为了完整起见,这是我使用的表格:
create table Accounting.Accounts
(
ID smallint identity primary key,
[Name] varchar(50) not null
constraint UQ_AccountName unique,
[Type] tinyint not null
constraint FK_AccountType foreign key references Accounting.AccountTypes
);
create table Accounting.Transactions
(
ID int identity primary key,
[Date] date not null default getdate(),
[Description] varchar(50) not null,
Reference varchar(20) not null default '',
Memo varchar(1000) not null
);
create table Accounting.TransactionParts
(
ID int identity primary key,
[Transaction] int not null
constraint FK_TransactionPart foreign key references Accounting.Transactions,
Account smallint not null
constraint FK_TransactionAccount foreign key references Accounting.Accounts,
Amount money not null,
VatRelated bit not null default 0
);
Run Code Online (Sandbox Code Playgroud)
演示可能的解释.
创建表脚本
SELECT *
INTO #T
FROM master.dbo.spt_values
CREATE NONCLUSTERED INDEX [IX_T] ON #T ([name] DESC,[number] DESC);
Run Code Online (Sandbox Code Playgroud)
查询一(返回35结果)
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY NAME) AS rn
FROM #T
)
SELECT c1.number,c1.[type]
FROM cte c1
JOIN cte c2 ON c1.rn=c2.rn AND c1.number <> c2.number
Run Code Online (Sandbox Code Playgroud)
查询二(与之前相同但将c2.[type]添加到选择列表使其返回0结果) ;
WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (ORDER BY NAME) AS rn
FROM #T
)
SELECT c1.number,c1.[type] ,c2.[type]
FROM cte c1
JOIN cte c2 ON c1.rn=c2.rn AND c1.number <> c2.number
Run Code Online (Sandbox Code Playgroud)
为什么?
未指定重复NAME的row_number(),因此它只选择适合所需输出列的最佳执行计划的任何一个.在第二个查询中,对于两个cte调用都是相同的,在第一个查询中,它选择不同的访问路径,结果是不同的row_numbering.
建议的解决方案
你是自己加入CTE的 ROW_NUMBER() over (order by t.[Date])
与可能预期的相反,CTE可能不会实现,这将确保自连接的一致性,因此您假设ROW_NUMBER()双方之间的相关性可能不存在于数据中[Date]存在重复的记录 .
如果您尝试ROW_NUMBER() over (order by t.[Date], t.[id])确保在绑定日期时row_numbering处于保证一致的顺序,该怎么办?(或者如果id不能执行此操作,可以区分记录的其他一些列/列组合)
| 归档时间: |
|
| 查看次数: |
2529 次 |
| 最近记录: |