簡體   English   中英

Oracle-如何編寫此SQL?

[英]Oracle - How to write this SQL?

在Oracle中,我有一張表記錄用戶的交易,如下表所示。 目標查詢不需要用戶列,只需在此處列出以供參考。

user1, transaction1, $10            <-row1
user1, transaction2, $20            <-row2
user1, transaction3, $5             <-row3
user1, transaction4, $100           <-row4
user2, ... ...
user3, ... ...

對於給定的用戶,將有一個貨幣限額,並且我需要找出貨幣總和> =給定貨幣限額的最小行,或者如果貨幣限額大於總和,則找出屬於該用戶的所有行。 返回的行必須按事務按升序排序。

例如,對於user1,給定的資金上限為$ 30。 然后必須返回row1和row2。 您無法返回row4,因為我們必須遵循交易順序。 如果給定的上限是$ 13,則必須返回row1和row2,因為row1不足以支付$ 13。 如果給定的上限是$ 136,則返回第1/2/3/4行,因為$ 10 + $ 20 + $ 5 + $ 100小於$ 136。

使用游標,我們可以使用存儲過程來解決此問題,但是我找不到一種優雅的方法來使用一些嵌套查詢和sum來實現此目的。 會非常感謝您的幫助!

您可以使用分析功能輕松完成此操作:

SELECT user_id, transaction_id, transaction_value
FROM   (SELECT user_id,
               transaction_id,
               transaction_value,
               SUM(transaction_value) 
                  OVER (PARTITION BY user_id 
                        ORDER BY transaction_id) AS running_total
        FROM   transactions)
WHERE  running_total <= :transaction_cap

按照ORDER BY子句(在這種情況下,該行的事務和所有具有較低ID的事務),以這種方式使用SUM可以提供當前行加上所有先前的行的總和,其中PARTITION BY子句指定的列相同。


再看一下問題,我意識到這是行不通的,因為它只會返回小於您要查找的值的值,而不是包含達到該點的值。 如果上一行小於目標總數,則以下修訂版將返回當前行。

SELECT user_id, transaction_id, transaction_value
FROM   (SELECT user_id,
               transaction_id,
               transaction_value,
               running_total,
               LAG(running_total) 
                   OVER (PARTITION BY user_id 
                         ORDER BY transaction_id) AS prior_total
        FROM   (SELECT user_id,
                       transaction_id,
                       transaction_value,
                       SUM(transaction_value) 
                          OVER (PARTITION BY user_id 
                                ORDER BY transaction_id) AS running_total
                FROM   transactions))
WHERE  prior_total < :transaction_cap or prior_total  is null

對於特定的上限,所有用戶均應相同:

SELECT user, transaction, amount
FROM MyTable t
WHERE ( SELECT SUM(ts.amount)
        FROM MyTable ts
        WHERE ts.user = t.user
          AND ts.transaction < t.transaction
      ) < @cap 
ORDER BY user, transaction

根據要求,這是一個R解決方案。 我不得不做出一些假設,將它們放在一起,在這里是:

  1. 資金限額信息存儲在單獨的表中,帶有適當的密鑰以加入交易數據
  2. 如果用戶的第一筆交易大於其資金限額,則不會為該用戶返回任何行

我在下面的代碼中發表了很多評論,但是如果您有任何疑問,請告訴我。 我首先創建了一些代表您的數據的假數據,然后在最底部運行您需要的查詢。

您可以考慮通過RODBC軟件包將數據庫與R接口。

#load needed package
require(plyr)
#Sed seet for reproducibility
set.seed(123)

#Make some fake data
dat <- data.frame(user = rep(letters[1:4], each = 4)
                  , transaction = rep(1:4, 4)
                  , value = sample(5:50, 16,TRUE) 
                  )
#Separate "data.frame" or table with the money cap info
moneyCaps <- data.frame(user = letters[1:4], moneyCap = sample(50:100, 4, TRUE))

#Ensure that items are ordered by user and transcation #. 
dat <- dat[order(dat$user, dat$transaction) ,]

#Merge the transaction data with the moneyCap data. This is equivalant to an inner join
dat <- merge(dat, moneyCaps)

#After the merge, the data looks like this:


user transaction value moneyCap
1     a           1    18       62
2     a           2    41       62
3     a           3    23       62
4     a           4    45       62
5     b           1    48       52
6     b           2     7       52
....

#Use the plyr function ddply to split at the user level and return values which are <=
#to the moneyCap for that individual. Note that if the first transaction for a user
#is greater than the moneyCap, then nothing is returned. Not sure if that's a possibility
#with your data

ddply(dat, "user", function(x) subset(x, cumsum(value) <= moneyCap))

#And the results look like:

  user transaction value moneyCap
1    a           1    18       62
2    a           2    41       62
3    b           1    48       52
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM