2013-01-22 20 views
7

ho una tabella come questa:Come aggiornare X% di righe da A, Y% di righe B, Z% di righe C

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

Ho una lista sul client in questo formato :

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 

Quando fatto, ho desidera assegnare il 40% di tipo 1 prodotti per instradare un, 40% al percorso B e 20% per route C. Poi il 50% di tipo 2 prodotti alla Route a e 50% di prodotti di tipo 2 su Route B, ecc.

C'è un modo per farlo in un singolo aggiornamento s ICHIARAZIONE?

Se non in una dichiarazione gigante, può essere fatto in una dichiarazione per tipo o una dichiarazione per rotta? Siccome al momento stiamo facendo uno per tipo + percorso, uno dei precedenti sarebbe un miglioramento.

+0

"Percentuale" nella vostra lista è piuttosto fuorviante se il numero che segue non è in realtà la percentuale . –

+0

Quale DBMS stai usando? Inoltre, puoi pubblicare codice o pseudocodice della tua attuale soluzione? –

+0

SQL Server 2008. E come è 0,4 non una percentuale? 40.0 è migliore? Presumo che 0.4 sia migliore perché 0.4 * count (*) è il numero di righe da aggiornare. – powlette

risposta

1

Ecco una dichiarazione Oracle che ho preparato prima di pubblicare che stavi usando SQL-Server, ma potrebbe darti qualche idea, anche se dovrai rollare la propria funzione analitica ratio_to_report usando CTE e self-join. Calcoliamo la proporzione cumulativa di ciascun tipo nelle tabelle dei prodotti e del percorso del cliente e facciamo un non equi-join sulle bande proporzionali corrispondenti. I dati di esempio che ho usato hanno alcuni arrotondamenti, ma questi si ridurranno per set di dati più grandi.

Ecco il programma di installazione:

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 

ed ecco la dichiarazione

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 

Questo dà il seguente risultato: -

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

ne dite qualcosa come

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

Forse non lo vedo, ma non è ancora questo un aggiornamento per tipo per percorso che sto già facendo? Inoltre, puoi "selezionare la percentuale X superiore" da una tabella in modo da poter saltare i passaggi di conteggio. Sto pensando che la soluzione, se ce n'è una, sarebbe una grande dichiarazione di un caso. – powlette

+0

sì. aggiorna un tipo/percorso per ogni istruzione di aggiornamento. – arunlalam

0

non so se una funzionalità simile esiste in SQL Server. In Oracle c'è la clausola SAMPLE. Sotto query seleziona il 10% delle righe da una tabella:

SELECT empno 
    FROM scott.emp 
SAMPLE (10) 
/

Poi l'aggiornamento sarebbe stato facile ... Forse si dovrebbe occupare simile esiste in SQL Server. Puoi anche contare le righe o i dati quindi calcolare la percentuale, quindi aggiornare ...

+0

Nei commenti, ho detto che stiamo facendo questo in un ciclo: I prodotti di aggiornamento impostano route = 'A' dove type = 1 e id in (seleziona il 40% più alto da prodotti dove type = 1 e route è null) Quindi l'aggiornamento non è difficile, ma mi piacerebbe ridurre il numero di aggiornamenti. – 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 ; 
Problemi correlati