问题描述
我们有两个表,Bucket和Student。我们必须在具有相同国家和城市的学生表中更新Bucket_id。但是在我的Bucket表中,我有两个针对相同国家和城市的Bucket ID,我们可以通过Desc来区分它们。
当我们在“学生”表中更新Bucket_id时,请牢记只能将70个学生分配给同一存储桶ID的时间。分配了70个学生后,它将使用另一个存储段ID更新
Bucket Table
BucketId Desc Country City
1 SOUTH PAK KHI
2 NORTH PAK KHI
Student中最初的Bucket_Id为空
预期结果如下:更新学生表中的Bucket_Id之后
Student Table
StudentId Country City BucketId
101 PAK KHI 1
102 PAK KHI 1
109 PAK KHI 1
201 PAK KHI 2
我尝试使用
update student std set Bucket_Id = (
select bucket_id from Bucket b where b.country=std.country and b.city = std.city and count(std.bucket_id) < 70
);
我们该怎么做?我们正在使用oracle 11g。
解决方法
您可以使用查询分配存储桶:
select s.*,b.bucketid
from (select s.*,row_number() over (partition by country,city order by studentid) - 1 as seqnum
from students s
) s join
(select b.*,city order by bucketid) - 1 as seqnum
from buckets b
) b
on s.seqnum between b.seqnum * 70 and (b.seqnum + 1) * 70 - 1;
Oracle在update
中没有很好的支持跨表处理更新,因此您需要使用merge
:
merge into
students s using
(select s.*,b.bucketid
from (select s.*,city order by studentid) - 1 as seqnum
from students s
) s join
(select b.*,city order by bucketid) - 1 as seqnum
from buckets b
) b
on s.seqnum between b.seqnum * 70 and (b.seqnum + 1) * 70 - 1
) ss
on s.studentid = ss.studentid
when matched then update
set s.bucketid = ss.bucketid;
,
看看这是否对您有用:
update students std set BucketId = (
select min(bucketid) from Bucket b where b.country=std.country and b.city = std.city)
where bucketid is null
and std.STUDENTID in (
SELECT x.STUDENTID FROM
(
select StudentId,rank() over(partition by country,city order by StudentId) rn
from students
) x where rn <= 3);
,
如果我正确理解了问题,也可以尝试以下方法:
MERGE INTO student t
USING (
SELECT
studentid,CAST(
ROW_NUMBER() OVER(
PARTITION BY country,city
ORDER BY studentid
) / 70 + 0.5
AS NUMBER(9,0)
) AS bucketid
FROM student
) s
ON (t.studentid=s.studentid)
WHEN MATCHED THEN UPDATE
SET bucketid = s.bucketid