Sql 如何将X%的行更新为A,Y%的行更新为B,Z%的行更新为C

Sql 如何将X%的行更新为A,Y%的行更新为B,Z%的行更新为C,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一张这样的桌子: 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, Perce

我有一张这样的桌子:

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%分配给路线C。然后将50%的2类产品分配给路线A,将50%的2类产品分配给路线B,以此类推

在一个update语句中是否有这样做的方法


如果不是在一个巨型语句中,那么它可以在每个类型的一个语句中完成,还是在每个路由的一个语句中完成?目前,我们正在对每种类型+路线进行一次测试,上述任何一项都将是一种改进。

类似的测试如何

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

我不知道SQL Server中是否存在类似的功能。在Oracle中有SAMPLE子句。 下面的查询从表中选择10%的行:

SELECT empno
  FROM scott.emp
SAMPLE (10)
/

那么你的更新将很容易。。。SQL Server中可能存在类似的smth。您也可以先计算行数或数据,然后计算百分比,然后更新…

这是我在发布您使用SQL Server之前准备的Oracle声明,但它可能会给您一些想法,尽管您必须使用CTE和自联接来运行自己的比率报告分析函数。我们计算产品和客户路由表中每种类型的累积比例,并在匹配比例带上进行非等联接。我使用的示例数据有一些舍入,但对于较大的数据集,这些舍入会减少

以下是设置:

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

如果下面的数字不是实际的百分比,那么列表中的百分比会产生误导。您使用的是哪种DBMS?另外,您可以发布当前解决方案的代码或伪代码吗?SQL Server 2008。0.4%怎么不是一个百分点?40.0更好吗?我认为0.4更好,因为0.4*count*是要更新的行数。@WaleedKhan对我来说似乎是百分比每行的百分比Type@WaleedKhan0.4表示40%。0.4=4/10=40/100,简单的数学。也许我没有看到,但这不是我已经在做的每种路线每种类型的更新吗?此外,您可以从表格中选择顶部X百分比,以便跳过计数步骤。我认为解决方案(如果有的话)将是一个大案例陈述。在评论中,我说我们是在循环中进行的:更新产品设置route='a',其中type=1,id在选择产品中的前40%,其中type=1,route为null,所以更新并不难,但我想减少更新的数量。
+----+------+----+
| 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  |
+----+------+----+
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 ;