3

I have an accounting table that contains a dollar amount field. I want to create a view that will return one row per penny of that amount with some of the other fields from the table.

So as a very simple example let's say I have a row like this:

PK     Amount     Date
---------------------------
123    4.80       1/1/2012

The query/view should return 480 rows (one for each penny) that all look like this:

PK      Date
-----------------
123     1/1/2012

What would be the most performant way to accomplish this? I have a solution that uses a table valued function and a temp table but in the back of my head I keep thinking there has got to be a way to accomplish this with a traditional view. Possibly a creative cross join or something that will return this result without having to declare too many resources in the form of temp tables, and tbf's etc. Any ideas?

4

2 回答 2

3

您可以使用CTE,如下所示:

WITH duplicationCTE AS 
(
    SELECT PK, Date, Amount, 1 AS Count
    FROM myTable
    UNION ALL
    SELECT myTable.PK, myTable.Date, myTable.Amount, Count+1
    FROM myTable
         JOIN duplicationCTE ON myTable.PK = duplicationCTE.PK
    WHERE Count+1 <= myTable.Amount*100
)
SELECT PK, Date
FROM duplicationCTE
OPTION (MAXRECURSION 0);

这是 SqlFiddle

并且,请注意 0。这意味着它可以无限运行(危险的顺便说一句)否则,32676 是您可以设置的最大递归数(默认为 100)。但是,如果您运行超过 32676 个循环,那么您可能需要重新考虑您的逻辑 :)

于 2012-04-13T18:12:32.763 回答
3

数字表的帮助下,您可以这样做:

select PK, [Date]
from YourTable as T
  inner join number as N
    on N.n between 1 and T.Amount * 100 

如果您周围没有并且想要测试它,您可以使用 master..spt_values。

declare @T table
(
  PK int,
  Amount money,
  [Date] date
)

insert into @T values
(123,    4.80,       '20120101')


;with number(n) as
(
  select number 
  from master..spt_values
  where type = 'P'
)
select PK, [Date]
from @T as T
  inner join number as N
    on N.n between 1 and T.Amount * 100 

更新:
来自 Jeff Moden 的一篇文章。
“数字”或“Tally”表:它是什么以及它如何替换循环。

Tally 表只不过是一个表,其中包含从 0 或 1 开始(我的从 1 开始)并上升到某个数字的非常好的索引序列号的单列。Tally 表中的最大数字不应该只是一些随意的选择。它应该基于您认为您将使用它的目的。我将 VARCHAR(8000) 与我的分开,所以它必须至少有 8000 个数字。由于我偶尔需要生成 30 年的日期,因此我将大部分生产 Tally 表保持在 11,000 或更多,即超过 365.25 天乘以 30 年。

于 2012-04-13T18:18:35.133 回答