我有以下数据结构
Customer | Order | Date | Amount | TransactionType
AABB | AB01 | 2012-06-01 | 3000 | Invoiced
AABB | AB01 | 2012-06-05 | 3000 | Payment
我需要从发票开具之日到付款之日重复我的数据。像这样;
Customer|Order|Date | AmountDue|AmountPaid|DatePaid |TransactionType
AABB |AB01 |2012-06-01| 3000 |NULL |2012-06-05|Invoiced
AABB |AB01 |2012-06-02| 3000 |NULL |2012-06-05|Invoiced
AABB |AB01 |2012-06-03| 3000 |NULL |2012-06-05|Invoiced
AABB |AB01 |2012-06-04| 3000 |NULL |2012-06-05|Invoiced
AABB |AB01 |2012-06-05| 3000 |3000 |2012-06-05|Payment
如何为此方案创建SQL脚本
答案 0 :(得分:2)
试试这个:
create table cust1
(
Customer varchar(20),
Orders varchar(10),
Date datetime,
Amount float,
TransactionType varchar(50)
)
INSERT INTO cust1
VALUES('AABB','AB01','2012-06-01',3000,'Invoiced'),
('AABB','AB01','2012-06-05',3000,'Payment')
DECLARE @stDate datetime,@eddate datetime
select @stDate =MIN(date),@eddate =MAX(date) from cust1
select c1.Customer,c1.Orders,DATEADD(DD,number,@stDate) as [date],
amount amountDue,
CASE WHEN (DATEADD(DD,number,@stDate)) = @eddate then amount else null end as amountPaid,
@eddate as datepaid,
CASE WHEN (DATEADD(DD,number,@stDate)) <> @eddate then 'Invoiced' else 'Payment' end as TransactionType
from master..spt_values p inner join cust1 c1
on right(cast(c1.date as DATE),2) <= (case when p.number = 0 then 1 else p.number end)
where type='p'and DATEADD(DD,number,@stDate) <=@eddate
答案 1 :(得分:1)
这是一次尝试,假设有两行,已付款,发票和付款行都存在,并且您正在尝试为一个特定客户/订单解决。
DECLARE @t TABLE
(
Customer VARCHAR(32),
[Order] VARCHAR(32),
[Date] DATE,
Amount INT,
TransactionType VARCHAR(32)
);
INSERT @t VALUES
('AABB','AB01','2012-06-01',3000,'Invoiced'),
('AABB','AB01','2012-06-05',3000,'Payment');
;WITH t AS (SELECT * FROM @t AS t WHERE t.Customer = 'AABB' AND t.[Order] = 'AB01'),
rng AS (SELECT s = MIN([Date]), e = MAX([Date]) FROM t),
n AS (SELECT TOP (DATEDIFF(DAY, (SELECT s FROM rng), (SELECT e FROM rng)))
n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1 FROM sys.all_objects
)
SELECT t.Customer, t.[Order], [Date] = DATEADD(DAY, n.n, t.[Date]),
AmountDue = Amount, AmountPaid = NULL, DatePaid = (SELECT e FROM rng),
t.TransactionType
FROM n CROSS JOIN t WHERE t.[Date] < (SELECT e FROM rng)
UNION ALL
SELECT t.Customer, t.[Order], t.[Date],
AmountDue = NULL, AmountPaid = Amount, DatePaid = t.[Date],
t.TransactionType
FROM t WHERE t.[Date] = (SELECT e FROM rng);
答案 2 :(得分:0)
首先,您需要汇总所需的数据以获取发票日期和付款日期。然后,您可以为其他记录生成序列。一种方法是使用递归CTE。但是,我通常会执行以下操作:
客户|订单|日期|金额| TRANSACTIONTYPE
select Customer, Order,
dateadd(d seqnum, InvoiceDate) as Date,
InvoiceAmount as AmountDue,
PaymentAmount as AmountPaid,
PaymentDate as DatePaid,
(case when dateadd(d seqnum, InvoiceDate) <> PaymentDate then 'Invoice' else 'Payment' end) as TransactionType
from (select customer, order,
max(case when TransactionType = 'Invoice' then amount end) as InvoiceAmount,
max(case when TransactionType = 'Payment' then amountend) as PaymentAmount
max(case when TransactionType = 'Invoice' then date end) as InvoiceDate,
max(case when TransactionType = 'Payment' then date end) as PaymentDate
from t
group by customer, order
) t join
(select row_number() over (order by (select NULL)) - 1 as seqnum
from INFORMATION_SCHEMA.Columns
) seq
on dateadd(d, 1, InvoiceDate, seqnum) <= PaymentDate
假设您有一张发票记录和一张付款记录。它还假设天数不是那么大。使用InformationSchema.Columns只是为了生成一个序列。
答案 3 :(得分:0)
好的,我知道OP已经被选中了解决方案。但我用行生成器发布我自己的解决方案。我认为这是一种优雅的方式。这是为了未来:
Fist,创建表格填充值:
create table #t (
Customer char(4), [Order] char(4), [Date] date, Amount money,
TransactionType varchar(50)
)
insert into #t values
( 'AABB','AB01','2012-06-01',3000,'Invoiced'),
( 'AABB','AB01','2012-06-05',3000,'Payment');
这里,行生成器和查询它自己:
declare @fromdate date
set @fromdate = '1/1/2001'
;WITH
Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
Nbrs ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 ),
all_dates as (
SELECT
dateadd( day, n , @fromDate) as [date]
FROM ( SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs ) D ( n )
),
all_intervals as (
select
t1.customer, t1.[order], t1.[date] as date_from, t1.amount as amount_due,
t2.[date] as date_paid
from
#t t1 inner join
#t t2 on t2.TransactionType = 'Payment'
and t1.customer = t2.customer and t1.[order] = t2.[order]
where t1.TransactionType = 'Invoiced'
)
select a.*, d.[date]
from all_intervals a
inner join all_dates d
on d.[date] between a.date_from and a.date_paid
结果:
customer order date_from amount_due date_paid date
-------- ----- ------------- ---------- ------------- -------------
AABB AB01 2012-06-01 00:00:003000 2012-06-05 00:00:002012-06-01 00:00:00
AABB AB01 2012-06-01 00:00:003000 2012-06-05 00:00:002012-06-02 00:00:00
AABB AB01 2012-06-01 00:00:003000 2012-06-05 00:00:002012-06-03 00:00:00
AABB AB01 2012-06-01 00:00:003000 2012-06-05 00:00:002012-06-04 00:00:00
AABB AB01 2012-06-01 00:00:003000 2012-06-05 00:00:002012-06-05 00:00:00
答案 4 :(得分:0)
这是一个通用的SQL版本,适用于没有一些更高级功能的RDBMS。还有列出尚未支付的帐户的额外好处。它假设您有一个可用的日历文件(真实或临时)
SELECT history.customer, history.order, calendar.calendar_date,
CASE WHEN history.transaction_type = 'Invoiced'
THEN history.amount END as amount_due,
CASE WHEN history.transaction_type = 'Payment'
THEN history.amount END as amount_paid,
history.transaction_type
FROM Transaction_History as history
JOIN Calendar
ON calendar.calendar_date < CURRENT_DATE + 1 DAY
AND ((calendar.calendar_date >= history.date
AND history.transaction_type = 'Invoiced')
OR (calendar.calendar_date = history.date
AND history.transaction_type = 'Payment'))
LEFT JOIN Transaction_History as exclusion
ON exclusion.customer = history.customer
AND exclusion.order = history.order
AND exclusion.transaction_type = 'Payment'
AND history.transaction_type = 'Invoiced'
AND exclusion.date <= calendar.calendar_date
WHERE exclusion.customer IS NULL
在我的系统(DB2)上测试 - SQLFiddle似乎已经失效。