我有一个票务明细表,用于存储交易信息。以下是表格数据的示例:
Ticket_Number Detail_type_ID Description Date_Created TotalAmount Barcode
1 11 Card Sale 1/1/16 5 123
1 1 Book 1/1/16 5
1 11 Card Red 1/1/16 -5 123
2 1 book 1/5/16 5
3 1 book 1/6/16 5
3 11 Card Red 1/6/16 -5 123
4 11 Card Sale 1/7/16 5 124
5 1 Book 1/7/16 5
5 11 Card Red 1/7/16 -5 124
6 11 Card Sale 1/8/16 5 123
6 1 Book 1/8/16 5
6 11 Card Red 1/8/16 -5 123
7 1 Book 1/9/16 5
7 11 Card Red 1/9/16 -5 124
我们出售礼品卡 - 5美元允许您购买2本书。礼品卡上装有2本书。您可以在上表中看到,在大多数情况下,我们会出售一张卡片,并立即兑换一本书。客户在某个时候回来,并购买另一本书,卡上剩余的余额。
我们希望了解的是:客户多久会回来并兑换余额,或者他们需要多长时间来消耗卡。正如您所看到的 - 条形码存储在详细信息表中,但是,我们会重新使用这些卡片,因此我们不希望这样会污染第一张卡片的数据。 Detail_Type_ID为' 11'是指卡片销售或兑换。根据上面的数据,这是I' m寻找的输出:
Barcode Days_between_usage Balance_still_remains
123 6 No
124 2 No
123(2) 0 Yes
"余额仍然存在"会告诉我这张卡还有余额。
如何运行查询以获取此输出?
编辑:
基于下面的答案,看起来第一步是将数据分解为我已经完成的销售和赎回。我不确定如何从这里开始。
Select barcode, date_created, Case When TotalAmount > 0 Then 'Sale' Else 'Redeem' end as SaleOrRedeem
From Ticketsdetails
Where (Date_Created > '1/1/16') and (Detail_Type_ID = '11') and (barcode In (select Barcode
From Ticketsdetails as td
where Date_Created > '1/1/16') and (Detail_Type_ID = '11') and Total Amount > 0)))
Order By Barcode, date_Created
返回:
Barcode Date_Created TransType
123 1/1/16 Sale
123 1/1/16 Redeem
123 1/6/16 Redeem
124 1/7/16 Sale
124 1/7/16 Redeem
124 1/7/16 Sale
123 1/8/16 Sale
123 1/8/16 Redeem
124 1/9/16 Redeem
答案 0 :(得分:6)
在黑暗中刺伤。我不确定我是否完全理解你的要求。
with Sales as (
select
t.Barcode,
t.Date_Created as Sale_Date,
row_number() over (partition by t.Barcode order by t.Sale_Date) as Load_Seq
from <Transactions> as t
where Description = 'Card Sale'
group by Barcode
),
RedemptionWindows as (
select
s1.Barcode,
s1.Load_Seq
s1.Sale_Date,
coalesce(s2.Sale_Date, dateadd(year, 1, s1.Sale_Date)) as End_Date,
from Sales as s1 left outer join Sales s2
on s2.Barcode = s1.Barcode and s2.Load_Seq = s1.Load_Seq + 1
)
select
Barcode
+ case
when Load_Seq > 1
then '(' + cast(Load_Seq as varchar(3)) + ')'
else '' end as Barcode,
Days_Between_Usage,
case when RedemptionCount < 2 then 'Yes' else 'No' Balance_Still_Remains,
5.00 - 2.50 * RedemptionCount as Balance_Remaining
from
RedemptionWindows as rw
cross apply
(
select
datediff(day,min(r.Date_Created),max(r.Date_Created)) as Days_Between_Usage,
count(*) as RedemptionCount
from <Transactions> as r /* redemptions */
where Description = 'Card Red'
and r.Barcode = rw.Barcode
and r.Date_Created >= rw.Sale_Date
and r.Date_Created < rw.End_Date
) r_summary
答案 1 :(得分:0)
您可以使用自联接或使用子查询来执行此操作。
这是一些伪代码
{{1}}
然后要获得最后一行,您将使用另一个生成所需行的查询来使用UNION。您可以使用CASE表达式根据剩余余额是否> 1来生成字符串。 0或不。并且可以使用子查询在条形码旁边的括号中生成数字。
答案 2 :(得分:0)
稍微复杂的代码可以为您提供解决方案。
我必须说 - 男人,重新使用条形码,在所呈现的场景中,将迫使你的解决方案始终在整个销售历史中向后看,只是为了设计重复使用事件的顺序&#39;在给定的背景下。
您最好不要重复使用条形码或对“重复使用订单”进行非规范化处理&#39;作为Ticketsdetails
上的新列。
...享受
SET NOCOUNT ON
go
--------------------------------------------------------------------------------
-- Isolate the card sale/redeem events (we are not interested in the books)
--
-- note the 'barcode_reuse_count' column
--------------------------------------------------------------------------------
DECLARE @price_per_book MONEY
SET @price_per_book = 5
SELECT
Ticket_Number, barcode, date_created,
--
CASE WHEN Description = 'Card Sale' THEN 1
ELSE 0
END AS is_event_of_sale /* is this an event of card sale? */,
--
CASE WHEN
Description = 'Card Sale' THEN (TotalAmount * 2) / @price_per_book /* Well, $5 HAS to mean TWO books... */
ELSE TotalAmount / @price_per_book
END AS Credit_Or_Debit_As_Books,
--
CONVERT(INT, NULL) AS barcode_reuse_order
INTO #card_events
FROM Ticketsdetails
WHERE Detail_Type_ID = '11'
go
--------------------------------------------------------------------------------
-- For each ticket, identify the ticket where the card in its 'barcode reuse'
-- incarnation was sold (although there should be one, and only one, barcode per
-- Ticket_Number, the query allows for more than one...)
--
-- Then, set 'barcode_reuse_order'
--------------------------------------------------------------------------------
WITH card_sale_event AS
(
SELECT card_event.Ticket_Number, card_event.barcode, MAX(card_event_sale.Ticket_Number) AS Ticket_Number_Of_Sale
FROM
#card_events card_event
INNER JOIN #card_events card_event_sale
ON(
card_event_sale.barcode = card_event.barcode
AND card_event_sale.is_event_of_sale = 1
AND card_event_sale.Ticket_Number <= card_event.Ticket_Number
)
GROUP BY card_event.Ticket_Number, card_event.barcode
)
UPDATE card_event
SET
barcode_reuse_order =(
SELECT
COUNT(DISTINCT prev_card_sale_event.Ticket_Number_Of_Sale)
/* card_event_sale may have many Ticket_Number_Of_Sale per barcode, one per Ticket_Number */
FROM card_sale_event prev_card_sale_event
WHERE
prev_card_sale_event.barcode = card_sale_event.barcode
AND prev_card_sale_event.Ticket_Number < card_sale_event.Ticket_Number_Of_Sale
)
FROM
#card_events card_event
INNER JOIN card_sale_event
ON(
card_sale_event.Ticket_Number = card_event.Ticket_Number
AND card_sale_event.barcode = card_event.barcode
)
go
--------------------------------------------------------------------------------
-- Le grand result
--------------------------------------------------------------------------------
SELECT
barcode +
CASE
WHEN barcode_reuse_order > 0 THEN '(' + CONVERT(VARCHAR, barcode_reuse_order + 1) + ')'
ELSE ''
END AS barcode,
--
CONVERT(INT, MAX(date_created)) -
CONVERT(INT, MIN(date_created)) AS Days_between_usage,
--
SUM(Credit_Or_Debit_As_Books) AS Balance
FROM #card_events
GROUP BY
barcode +
CASE
WHEN barcode_reuse_order > 0 THEN '(' + CONVERT(VARCHAR, barcode_reuse_order + 1) + ')'
ELSE ''
END
go
--------------------------------------------------------------------------------
-- Clean-up
--------------------------------------------------------------------------------
DROP TABLE #card_events
go
我使用下面的脚本上传了给定的数据。
IF EXISTS(SELECT * FROM sys.tables WHERE name = 'Ticketsdetails')
DROP TABLE Ticketsdetails
go
CREATE TABLE Ticketsdetails(
Ticket_Number INT,
Detail_type_ID INT,
Description VARCHAR(32),
Date_Created DATETIME,
TotalAmount MONEY,
Barcode VARCHAR(16)
)
go
insert into Ticketsdetails values(1, 11, 'Card Sale', '20160101', 5, '123')
insert into Ticketsdetails values(1, 1, 'Book', '20160101', 5, NULL)
insert into Ticketsdetails values(1, 11, 'Card Red', '20160101', -5, '123 ')
insert into Ticketsdetails values(2, 1, 'book', '20160105', 5, NULL)
insert into Ticketsdetails values(3, 1, 'book', '20160106', 5, NULL)
insert into Ticketsdetails values(3, 11, 'Card Red', '20160106', -5, '123')
insert into Ticketsdetails values(4, 11, 'Card Sale', '20160107', 5, '124')
insert into Ticketsdetails values(5, 1, 'Book', '20160107', 5, NULL)
insert into Ticketsdetails values(5, 11, 'Card Red', '20160107', -5, '124')
insert into Ticketsdetails values(6, 11, 'Card Sale', '20160108', 5, '123')
insert into Ticketsdetails values(6, 1, 'Book', '20160108', 5, NULL)
insert into Ticketsdetails values(6, 11, 'Card Red', '20160108', -5, '123')
insert into Ticketsdetails values(7, 1, 'Book', '20160109', 5, NULL)
insert into Ticketsdetails values(7, 11, 'Card Red', '20160109', -5, '124')
go