簡體   English   中英

幫助硬SQL查詢根據每日總計更新到匯總表

[英]Help with hard sql query to update based on daily totals to summary table

以下是我的sql server 2005表結構:

產品(productID INT PK,...)

產品出價(productID INT,userID INT,創建的DATETIME)

用戶(UserID INT PK,TOTALBIDS INT)

每天,用戶可以對所有產品進行任意多次的出價。 有一個sql作業會定期運行,該作業會計算用戶執行的總出價,並將總出價放入TOTALBIDS字段中。

問題是,我們的業務規則要求我們在任何一天最多只能計算10個出價。

因此,更新查詢必須按天分組,如果用戶在產品上的總出價超過10,則當天只使用10。

例如,第1天第1天總共出價5次#2第2天總共出價15次#3第10次出價

(假設總共3天),該用戶的bidCount將為5 + 10 + 10 = 25(而不是30)。

在單個查詢中有可能嗎?

您無需說出要如何處理結果,但可以確定每天選擇用戶最早的10個出價:

with ProductBidsRanked(productID, userID, Created, rk) as (
  select
    productID, userID, Created,
    row_number() over (
      partition by userID, dateadd(datediff(day,0,Created),0)
      order by Created
    )
)
  select productID, userID, Created
  from ProductBidsRanked
  where rk <= 10

當然,如果您只需要總數,並且想在總數超過10時將其替換為10,那會更容易:

with PartialAgg(userID,countOr10) as (
  select
    userID,
    case when count(*) > 10 then 10 else count(*) end
  from ProductsBids
  group by userID, dateadd(datediff(day,0,Created),0)
)
  select
    userID, sum(countOr10) as BidsAdjusted
  from PartialAgg
  group by userID;

對評論的回應:

您說要將其添加到用戶的出價計數中,但是出價計數不是任何表中的列名稱。 也許您的意思是TOTALBIDS,因此例如,如果第二個查詢對您有效,則可以執行以下操作:

with PartialAgg(userID,countOr10) as (
  select
    userID,
    case when count(*) > 10 then 10 else count(*) end
  from ProductsBids
  group by userID, dateadd(datediff(day,0,Created),0)
), FullAgg(userID,BidsAdjusted) as (
  select
    userID, sum(countOr10) as BidsAdjusted
  from PartialAgg
  group by userID
)
  update users set
    TOTALBIDS = TOTALBIDS + BidsAdjusted
  from users join FullAgg
  on FullAgg.userID = users.userID

僅供參考,這里有一些SQL Server特定的東西-ANSI不允許CTE進行UPDATE,而且我也沒有確認T-SQL的古怪UPDATE .. FROM是否可以與CTE結合使用。

無論如何,鑒於這似乎是一種更新,您只會很少運行,而絕不會同時運行,因此將我的第一個建議的結果(以您的目的為准)插入臨時表並將更新基於此是最明智的選擇那。

CREATE TABLE dbo.ProductBids(ProductID INT, UserID INT, Created DATETIME);

CREATE TABLE dbo.Users(UserID INT, TotalBids INT);

INSERT dbo.Users(UserID) SELECT 1 UNION ALL SELECT 2;

INSERT dbo.ProductBids 
           SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()-1
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 1, GETDATE()
UNION ALL  SELECT 1, 2, GETDATE()
UNION ALL  SELECT 1, 2, GETDATE()
UNION ALL  SELECT 1, 2, GETDATE();

UPDATE u 
SET TotalBids = x.TotalBids
FROM
(
    SELECT
        UserID, 
        TotalBids = SUM(CASE WHEN c > 10 THEN 10 ELSE c END)
    FROM
    (
        SELECT
            UserID,
            c = COUNT(*)
        FROM
            dbo.ProductBids
        GROUP BY
            UserID,
            DATEADD(DAY, 0, DATEDIFF(DAY, 0, Created))  
    ) AS y
    GROUP BY UserID
) AS x
INNER JOIN dbo.Users AS u
ON x.UserID = u.UserID;

GO

SELECT UserID, TotalBids FROM dbo.Users;

GO

DROP TABLE dbo.Users, dbo.ProductBids;

但是,總的來說,當您可以從現有數據中獲取信息時,我並不喜歡存儲總數。 問題在於,只能保證在您運行UPDATE語句的時間與下一次任何DML操作再次發生在ProductBids表之間的時間內,Users表中的數據是准確的。

我認為您可以使用匯總+案例聲明來執行此操作。 就像是:

declare @t table (a int, b int)

insert into @t values(1, 5)
insert into @t values(1, 15)
insert into @t values(1, 10)


select a, sum( case when b>10 then 10 else b end) 
from @t
group by a

case語句確保如果值大於10,則您永遠不會添加超過10

暫無
暫無

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

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