row_number() over (partition by....order by...)用法
表结构:表A:名称,创建人
表B:表Aid,接收人
表C:表Aid,内容,发送人,接收人,状态
需求分析:创建人发送内容给接收人消息,接收人回复。创建人,接收人登陆入消息页面,需看到了解到属于自己的消息以及自己创建的消息是否有回复。
解析:当admin创建了一条消息给longer,会往A,B,C中插入数据,表C的状态为1为已读。admin登陆页面显示为:名称,发起人为admin,状态为已读
当longer登陆时页面显示为:名称,发起人admin,状态为未读。
若longer查看消息并回复一条消息时。 longer回到页面,则显示为已读,即使在上一步,不回复,查看了也是显示为已读状态。
当admin登陆到消息页面时,该信息状态显示为未读,若longer没有回复消息,那么显示的就是已读。
根据表结构以及需求,剖析出来就是要分解为两个查询语句,可能会更好入手解决,面对可以解析为两手着手的问题,一般就会习惯于分成两步考虑。
首先考虑先解决创建人创建消息的查询,这里要解决的问题就是,我是创建人,发送到的longer消息被读取回复的情况。也就是通过表A查询出本次登陆用户创建的消息以及对应到表C里是否有人回复并未读取的状况。那问题就来了,若我这条消息同时发送给了三个人,九点的时候有人回复了,我登陆并查看后,十点另一个人回复了,然后再通过普通的级联查询已经不能满足,也就是说此时查询会查询出两条数据状态分别为1和2,已读和未读。那此时要求的就是当有2时候要显示未读,去除1的数据。自然就会想到排序分组,排序后给其分状态位标识。这么说可能比较难理解。直接来看句子:
SELECT * FROM ( select ROW_NUMBER() OVER(PARTITION BY m.id ORDER BY c.content_status desc)RN, m.id,m.title,m.establish_human humanid, decode(m.delflag,'0','0') status, nvl(c.content_status,'1') type from ns_message m left join ns_message_content c on m.establish_human=c.receive_human and m.id=c.messageid where m.delflag=0 and m.establish_human='adminID' )where rn=1
注意:ROW_NUMBER函数是先排序后再计算行号码的。翻译到我们日常理解就是有你,你则是1他是2,没有你他进阶为1.
同理推断出,admin是接收者的消息(这里直接贴句子):
select rn, id, title, humanid, status, type from (select ROW_NUMBER() OVER(PARTITION BY m.id, m.title order by c.content_status) RN, m.id, m.title, m.establish_human humanid, decode(m.delflag, '0', '1') status, c.content_status type from ns_message_human h left join ns_message m on h.messageid = m.id left join ns_message_content c on m.id = c.messageid where m.delflag = 0 and h.receivehumanid = 'adminID' and c.receive_human = 'adminID')
最后就是利用union进行整合,最终sql语句就是:
select * from ( SELECT * FROM ( select ROW_NUMBER() OVER(PARTITION BY m.id ORDER BY c.content_status desc)RN, m.id,m.title,m.establish_human humanid, decode(m.delflag,'0','0') status, nvl(c.content_status,'1') type from ns_message m left join ns_message_content c on m.establish_human=c.receive_human and m.id=c.messageid where m.delflag=0 and m.establish_human='402884124a3c15e9014a3c1aa0670001' )where rn=1 union select rn, id, title, humanid, status, type from (select ROW_NUMBER() OVER(PARTITION BY m.id, m.title order by c.content_status) RN, m.id, m.title, m.establish_human humanid, decode(m.delflag, '0', '1') status, c.content_status type from ns_message_human h left join ns_message m on h.messageid = m.id left join ns_message_content c on m.id = c.messageid where m.delflag = 0 and h.receivehumanid = '40288567400553f501400554c7b00044' and c.receive_human = '40288567400553f501400554c7b00044') where rn = 1)
这里只是大概对于ROW_NUMBER的使用进行了举例子,具体的含义概念,谷歌一番,可能效果会更好点。我们代码世界的理解方式:看+敲=理解