2013-01-22 42 views
7

的ž%,我有這樣的一個表:如何更新行的X%,以A,行B的Y%,行至C

Products 
(
    ID int not null primary key, 
    Type int not null, 
    Route varchar(20) null 
) 

我有這種格式在客戶端上的清單:

Type=1, Percent=0.4, Route=A 
Type=1, Percent=0.4, Route=B 
Type=1, Percent=0.2, Route=C 
Type=2, Percent=0.5, Route=A 
Type=2, Percent=0.5, Route=B 
Type=3, Percent=1.0, Route=C 
...etc 

完成後,我想分配類型的40%1的產品路線A,40%至路線B和20%至路線℃。然後50的2型產品%至路徑A和2型產品B線50%,等等。

是否有某種方式在單個更新s到這樣做tatement?

如果不是在一個巨大的聲明,是否可以在每一個類型語句或每一個路由聲明做了什麼?目前我們正在爲每種類型+路線做一件,上述任何一項都會有所改進。

+0

「百分比」 在列表中是相當如果接下來的數字實際上不是百分比,則會引起誤導。 –

+0

您正在使用哪些DBMS?另外,您可以發佈當前解決方案的代碼或僞代碼嗎? –

+0

SQL Server 2008. 0.4如何不是百分之一?是40.0更好?我假設0.4更好,因爲0.4 * count(*)是要更新的行數。 – powlette

回答

1

下面是我給你貼,你是使用SQL-Server之前準備一個Oracle的聲明,但它可能給你一些想法,但你將不得不使用CTE和自連接來推出自己的ratio_to_report分析函數。我們計算產品和客戶路線表中每種類型的累計比例,並在匹配的比例頻帶上進行非均等連接。我使用的樣本數據有一些舍入,但對於較大的數據集,這些數據會減少。

這裏的設置:

create table products (id int not null primary key, "type" int not null, route varchar (20) null); 
create table clienttable ("type" int not null, percent number (10, 2) not null, route varchar (20) not null); 
insert into clienttable ("type", percent, route) values (1, 0.4, 'A'); 
insert into clienttable ("type", percent, route) values (1, 0.4, 'B'); 
insert into clienttable ("type", percent, route) values (1, 0.2, 'C'); 
insert into clienttable ("type", percent, route) values (2, 0.5, 'A'); 
insert into clienttable ("type", percent, route) values (2, 0.5, 'B'); 
insert into clienttable ("type", percent, route) values (3, 1.0, 'C'); 

insert into products (id, "type", route) values (1, 1, null); 
insert into products (id, "type", route) values (2, 1, null); 
insert into products (id, "type", route) values (3, 1, null); 
insert into products (id, "type", route) values (4, 1, null); 
insert into products (id, "type", route) values (5, 1, null); 
insert into products (id, "type", route) values (6, 1, null); 
insert into products (id, "type", route) values (7, 1, null); 
-- 7 rows for product type 1 so we will expect 3 of route A, 3 of route B, 1 of route C (rounded) 

insert into products (id, "type", route) values (8, 2, null); 
insert into products (id, "type", route) values (9, 2, null); 
insert into products (id, "type", route) values (10, 2, null); 
insert into products (id, "type", route) values (11, 2, null); 
insert into products (id, "type", route) values (12, 2, null); 
-- 5 rows for product type 2 so we will expect 3 of route A and 2 of route B (rounded) 

insert into products (id, "type", route) values (13, 3, null); 
insert into products (id, "type", route) values (14, 3, null); 
-- 2 rows for product type 3 so we will expect 2 of route C 

和這裏的聲明

select prods.id, prods."type", client.route cr from 
(
select 
p.id, 
p."type", 
row_number() over (partition by p."type" order by p.id)/count (*) over (partition by p."type") cum_ratio 
from 
products p 
) prods 
inner join 
(
select "type", route, nvl (lag (cum_ratio, 1) over (partition by "type" order by route), 0) ratio_start, cum_ratio ratio_end from 
(select "type", route, sum (rr) over (partition by "type" order by route) cum_ratio 
from (select c."type", c.route, ratio_to_report (c.percent) over (partition by "type") rr from clienttable c))) client 
on prods."type" = client."type" 
and prods.cum_ratio >= client.ratio_start and prods.cum_ratio < client.ratio_end 

這給出了以下結果: -

+----+------+----+ 
| ID | type | CR | 
+----+------+----+ 
| 1 | 1 | A | 
| 2 | 1 | A | 
| 3 | 1 | B | 
| 4 | 1 | B | 
| 5 | 1 | B | 
| 6 | 1 | C | 
| 8 | 2 | A | 
| 9 | 2 | A | 
| 10 | 2 | B | 
| 11 | 2 | B | 
| 13 | 3 | C | 
+----+------+----+ 
0

如何像

--For updating type 1, set every route for type 1 as null. 

UPDATE MyTable 
SET [Route] = null 
WHERE [Type] = '1' 

--Update Route A(40%) 
DECLARE @myVal int; 
SET @myVal =CAST(0.4*(SELECT COUNT(*) FROM myTable WHERE [Type]='1') AS INT); 
WITH tab AS 
    (
    SELECT TOP (@myVal) * 
    FROM myTable 
    ) 
UPDATE tab 
SET  [Route] = 'A' 
WHERE [Route] is null 

--Update Route B (40%) 
DECLARE @myVal int; 
SET @myVal =CAST(0.4*(SELECT COUNT(*) FROM myTable WHERE [Type]='1') AS INT); 
WITH tab AS 
    (
    SELECT TOP (@myVal) * 
    FROM myTable 
    ) 
UPDATE tab 
SET  [Route] = 'B' 
WHERE [Route] is null 


--Update Route C (20%) 
DECLARE @myVal int; 
SET @myVal =CAST(0.2*(SELECT COUNT(*) FROM myTable WHERE [Type]='1') AS INT); 
WITH tab AS 
    (
    SELECT TOP (@myVal) * 
    FROM myTable 
    ) 
UPDATE tab 
SET  [Route] = 'C' 
WHERE [Route] is null 
+0

也許我沒有看到它,但是這不是每個類型的每個類型的更新,我已經在做什麼?此外,您可以從表中選擇「前X%」,這樣您就可以跳過計數步驟。我認爲解決方案,如果有的話,將是一個大案例陳述。 – powlette

+0

是的。它爲每個更新語句更新一個類型/路由。 – arunlalam

0

我不知道類似的功能在SQL Server中存在。在Oracle中有SAMPLE子句。 下面的查詢選擇從表中的行10%:

SELECT empno 
    FROM scott.emp 
SAMPLE (10) 
/

那麼你的更新會很容易......也許SMTH存在類似SQL Server中。您還可以指望的行或數據,那麼計算的百分比,然後更新...

+0

在評論中,我說我們正在做一個循環:更新產品set type ='A'其中type = 1和id in(從type = 1和route爲null的產品中選擇top 40%)因此,更新並不難,但我想減少更新的數量。 – powlette

0
WITH po AS 
    (SELECT 
     ID, 
     Type, 
     ROW_NUMBER() OVER (PARTITION BY Type 
          ORDER BY ID 
         ) AS Rn, 
     COUNT(*) OVER (PARTITION BY Type) AS CntType 
    FROM 
      Products 
)  
, ro AS 
    (SELECT 
     Type, 
     Route, 
     (SELECT SUM(rr.Percent) 
      FROM Route AS rr 
      WHERE rr.Type = r.Type 
      AND rr.Route <= r.Route 
     ) AS SumPercent 
    FROM 
      Routes AS r 
) 
UPDATE p 
SET p.Route = 
      (SELECT MIN(ro.Route) 
       FROM ro 
       WHERE ro.Type = po.Type 
       AND ro.SumPercent >= po.Rn/po.CntType 
      ) 
FROM Products AS p 
    JOIN 
     po ON po.ID = p.ID ; 
相關問題