SQL:从startdate到enddate重复记录

时间:2012-08-02 15:09:03

标签: sql sql-server sql-server-2008-r2

我有以下数据结构

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脚本

5 个答案:

答案 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

You can try it.

答案 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似乎已经失效。