我帅故我在

专注于:SQL Server、性能调优、数据挖掘(DM)、商业智能(BI)。
兼职SQL Server性能调优顾问。

统计

常用链接

积分与排名

DBA

博客

门户

其它

性能调优

阅读排行榜

评论排行榜

简单实用SQL脚本Part9:纵向回填信息

       需求:我们的一个系统有这样一个功能:记录用户访问网站页面的轨迹,比如A->B->C->DABCD表示不同的页面URL),在系统的业务上用户可以使用帐号访问网站,也可以使用匿名访问网站,而用户使用的机器已经被标识为一个GUID,所以当用户使用了匿名访问AB页面后在C页面使用帐号登陆了系统,那么为了对用户进行分析,我们需要把AB页面的登录名设置登陆的账号,这样用户的访问过程就有了一个完整的一条线。(如图1所示)

       注意1的是一台机器(GUID)有可能使用了多个帐号进行登陆,那么同一个GUID就有可能包含了匿名、帐号a、帐号b的交替记录。(如图1所示)

       注意2这个表中的记录是按照自增ID值来进行排序,你也可以通过访问的时间来排序。下面的操作都是基于自增ID排序的。

       注意3纵向回填信息需要包括向上和向下回填信息。因为用户有可能使用帐号登陆了系统之后退出了系统再匿名访问,所以这个回填的过程除了要向上回填用户名之外还得向下回填用户名才是合理的。

       注意4必须先执行完向上回填再执行向下回填。

 

(图1 


--生成测试数据
if exists (select * from sysobjects where id = OBJECT_ID('[t_RLoginname]'and OBJECTPROPERTY(id, 'IsUserTable'= 1
DROP TABLE [t_RLoginname]

CREATE TABLE [t_RLoginname] (
[ID] [int]  NOT NULL,
[Loginname] [varchar]  (50NULL,
[Guid] [varchar]  (50NULL)

INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10701389,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10701581,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10701621,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10701658,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10701828,'17851307','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10702068,'17851307','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10702226,'17851307','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10702361,'17851307','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704102,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704166,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704559,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704615,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704715,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10704766,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10705208,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10705317,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10705637,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10705774,'21958792','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10780602,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10781073,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')
INSERT [t_RLoginname] ([ID],[Loginname],[Guid]VALUES ( 10781162,'未知','7E5863ED-53B2-5245-DE1F-0D08CC743356')

 

逻辑:找出未知用户需要回填的账号:找到比当前ID大的;并且loginname不为“未知”的那条记录;并且是相当的guid的记录。

 

(图2原理图) 

 

向上回填:使用下面的查询语句得到的结果如图3所示

--查询出向上未知用户需要回填的loginname
select ID,guid,loginname,new_loginname
    
from (
        
select ID,guid,loginname,new_loginname = 
        (
        
SELECT TOP 1 loginname from [t_RLoginname] where
            id=(select min(id) from [t_RLoginname] 
                
where id>a.id and loginname <>'未知' AND guid = a.guid)
        )
        
from [t_RLoginname] as a
        
where a.loginname = '未知'
    ) as b
    
where b.new_loginname is not null

 


 (图3:向上对应未知用户)

--向上回填
--插入到临时表
select ID,guid,loginname,new_loginname
    
into [t_RLoginname_up]
    
from (
        
select ID,guid,loginname,new_loginname = 
        (
        
SELECT TOP 1 loginname from [t_RLoginname] where
            id=(select min(id) from [t_RLoginname] 
                
where id>a.id and loginname <>'未知' AND guid = a.guid)
        )
        
from [t_RLoginname] as a
        
where a.loginname = '未知'
    ) as b
    
where b.new_loginname is not null

--更新记录
update a set a.loginname = b.new_loginname
    
from [t_RLoginname] as a,
    
[t_RLoginname_up] as b
    
where a.ID = b.ID 
    
and a.guid = b.guid

 

向下回填:这条语句和向上回填的不同主要是minmaxid>a.idid<a.id的区别。

--向下回填
--插入到临时表
select ID,guid,loginname,new_loginname
    
into [t_RLoginname_down]
    
from (
        
select ID,guid,loginname,new_loginname = 
        (
        
SELECT TOP 1 loginname from [t_RLoginname] where
            id=(select max(id) from [t_RLoginname] 
                
where id<a.id and loginname <>'未知' AND guid = a.guid)
        )
        
from [t_RLoginname] as a
        
where a.loginname = '未知'
    ) as b
    
where b.new_loginname is not null


--更新记录
update a set a.loginname = b.new_loginname
    
from [t_RLoginname] as a,
    
[t_RLoginname_down] as b
    
where a.ID = b.ID 
    
and a.guid = b.guid


-------------------华丽分割线-------------------

作者:听风吹雨

出处:http://gaizai.cnblogs.com/

版权:本文版权归作者和博客园共有

转载:欢迎转载,不过记得留下买路钱

邮箱:gaizai@126.com

格言:不喜欢是因为你不会 && 因为会所以喜欢

-------------------华丽分割线-------------------

posted on 2010-09-06 14:35 听风吹雨 阅读(1713) 评论(10) 编辑 收藏

评论

#1楼 2010-09-06 15:31 leo gu      

不错。在具体应用的时候很有用。
不过在更新的时候能不用临时表最好。
 回复 引用 查看   

#2楼 2010-09-07 00:08 zqonline      

博主,发一个i170的邀请码吧。

admin[at]zimo.me
 回复 引用 查看   

#3楼[楼主] 2010-09-08 10:37 听风吹雨      

@leo gu
如果不使用临时表,那么在大数据量的表中直接操作更新会很慢。
 回复 引用 查看   

#4楼[楼主] 2010-09-08 10:37 听风吹雨      

@zqonline
不好意思,我的i170没有邀请码啊。
 回复 引用 查看   

#5楼 2010-09-08 15:38 五味果      

用户行为分析的好东西,最好能做成一个通用的组件。  回复 引用 查看   

#6楼 2010-09-08 15:43 五味果      

请教下:
用户的GUID是怎么进行分配和验证的?
 回复 引用 查看   

#7楼 2010-09-08 15:52 五味果      

现在能想到的方式就是给客户端写cookies。  回复 引用 查看   

#8楼[楼主] 2010-09-08 21:03 听风吹雨      

@五味果
我的做法是使用Flex,调用服务器的远程接口获取服务器的GUID,并把GUID保存到客户端的SharedObject中。
 回复 引用 查看   

#9楼[楼主] 2010-09-08 21:04 听风吹雨      

@五味果
做成通用的组件比较不现实。
 回复 引用 查看   

#10楼 2010-09-14 17:56 leo gu      

@听风吹雨
可以用基于连接的临时表,当数据库连接断开时这个表自动消失,也不会影响到系统的其它逻辑。
 回复 引用 查看   

发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1802927 Jk7CNdiaUuw=