2013-01-22 10 views
7

Mam tabeli jak poniżej:Jak zaktualizować X% wierszy A, Y% wierszy B, Z% wierszy C

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

Mam listę na kliencie w tym formacie :

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 

Po zakończeniu ja jak przypisanie 40% Typ 1 produktów na drodze a, 40% do drogi B i 20% C, a następnie do trasy 50% 2 typu produktów do Droga a i 50% produktów typu 2 na trasie B itd.

Czy jest jakiś sposób na zrobienie tego w pojedynczej aktualizacji s tatement?

Jeśli nie w jednym gigantycznym oświadczeniu, czy można to zrobić za pomocą jednego zdania na typ lub jednego oświadczenia na trasę? Jak obecnie robimy jeden na typ + trasę, którekolwiek z powyższych będzie poprawy.

+0

"procent" na liście jest raczej wprowadzanie w błąd, jeśli liczba, która następuje, nie jest w rzeczywistości procentem . –

+0

Którego DBMS używasz? Czy możesz też opublikować kod lub pseudokod bieżącego rozwiązania? –

+0

SQL Server 2008. A jak to 0,4 nie jest procesem? Czy 40.0 jest lepsze? Zakładam, że 0.4 jest lepsze, ponieważ 0,4 * liczba (*) to liczba wierszy do zaktualizowania. – powlette

Odpowiedz

1

Oto oświadczenie Oracle, które przygotowałem, zanim napisałeś, że korzystasz z SQL-Servera, ale to może dać ci kilka pomysłów, ale będziesz musiał uruchom własną funkcję analityczną ratio_to_report przy użyciu CTE i self-join. Obliczamy skumulowaną proporcję każdego rodzaju w tabelach produktów i trasach klienta i wykonujemy non equi-join na pasujących pasmach proporcji. Przykładowe dane, które wykorzystałem, mają pewne zaokrąglenia, ale zmniejszą się w przypadku większych zestawów danych.

Oto konfiguracja:

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 

i oto oświadczenie

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 

To daje następujący wynik: -

+----+------+----+ 
| 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

Jak o czymś takim

--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

Może nie widzę tego, ale czy to wciąż jedna aktualizacja każdego typu na trasę, którą już robię? Możesz też "wybrać górny X procent" z tabeli, aby pominąć kroki zliczania. Myślę, że rozwiązanie, jeśli takie istnieje, byłoby wielkim stwierdzeniem w sprawie sprawy. – powlette

+0

tak. aktualizuje jeden typ/trasę dla każdej instrukcji aktualizacji. – arunlalam

0

ja nie wiem, czy podobną funkcjonalność istnieje w SQL Server. W Oracle istnieje klauzula SAMPLE. Poniżej zapytania wybiera 10% wierszy z tabeli:

SELECT empno 
    FROM scott.emp 
SAMPLE (10) 
/

Wtedy twój zmiana byłaby łatwa ... Może czymś podobnym istnieje w SQL Server. Możesz także policzyć wiersze lub dane, a następnie oblicz procent, a następnie zaktualizować ...

+0

W komentarzach powiedziałem, że robimy to w pętli: Update products ustaw trasę = 'A', gdzie type = 1 and id in (wybierz najlepsze 40 procent z produktów, gdzie typ = 1 i trasa jest zerowa) Więc aktualizacja nie jest trudne, ale chciałbym zmniejszyć liczbę aktualizacji. – 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 ;