2

私は次のデータ構造を持っています

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スクリプトを作成するにはどうすればよいですか

4

5 に答える 5

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
于 2012-08-02T15:37:05.083 に答える
1

これは、2つの行があり、支払いが行われ、請求書と支払いの両方の行が存在し、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);
于 2012-08-02T15:57:32.610 に答える
0

まず、請求日と支払い日を取得するために必要なデータを要約する必要があります。次に、追加レコードのシーケンスを生成できます。これを行う1つの方法は、再帰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

これは、1つの請求書レコードと1つの支払いレコードがあることを前提としています。また、日数はそれほど多くないことを前提としています。InformationSchema.Columnsの使用は、シーケンスを生成することだけです。

于 2012-08-02T15:40:40.323 に答える
0

OK、OPがまだソリューションとして選択されていることを知っています。しかし、私は行ジェネレーターを使用して独自のソリューションを投稿しています。これはエレガントな方法だと思います。将来のためにここに:

まず、テーブルに値を入力して作成します。

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

あなたはそれを試すことができます。

于 2012-08-02T16:10:40.660 に答える
0

これは、いくつかの優れた機能を備えていないRDBMS用の一般的なSQLバージョンです。まだ支払われていないアカウントも一覧表示するという追加の利点があります。利用可能なカレンダーファイル(実際または一時的)があることを前提としています

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がダウンしているようです。

于 2012-08-02T16:20:16.310 に答える