代码改变世界

排序规则引起的冲突问题

2012-09-20 22:21  yezhi  阅读(334)  评论(0)    收藏  举报

最近在工作中碰到一例因排序规则而导致的冲突问题,运行环境是SQL 2008,具体代码如下:

  1. DECLARE @URL VARCHAR(500),  
  2.     @startdate DATETIME,  
  3.     @enddate DATETIME,  
  4.     @Identifier VARCHAR(20);      
  5.   
  6. SELECT @URL = '/articlenet/article.aspx',        
  7.        @startdate = '2010-02-01',     
  8.        @enddate = '2010-02-28',  
  9.        @Identifier = 'id';  
  10.   
  11. SELECT CAST(au.PopulateDate AS dateAS DateViewed  
  12.            ,qs.Value  
  13.            ,COUNT(1) AS PageViews  
  14.            ,COUNT(  
  15.               DISTINCT CASE WHEN au.UserId = 6264375 THEN au.FPID   
  16.                               ELSE du.UserGUID  END  
  17.                  ) AS DistinctUsers  
  18. FROM Dim_URL u (NOLOCK)  
  19.     JOIN dbo.Agg_User_Archive au  (NOLOCK)   
  20.         ON u.URLKey  = au.URLKey   
  21.     JOIN Dim_QueryString qs  (NOLOCK)   
  22.         ON au.AggUserId  = qs.AggUserId   
  23.     JOIN dbo.Dim_UserId du (NOLOCK)   
  24.         ON du.UserKey  = au.UserId   
  25. WHERE URL  = @URL  
  26.     AND au.PopulateDate  > @startdate  
  27.     AND au.PopulateDate  < @enddate  
  28.     AND qs.Identifier  = @Identifier  
  29. GROUP BY CAST(au.PopulateDate AS DATE), Value  
  30. ORDER BY DateViewed DESC, Value;  
  31.   
  32. --Msg 457, Level 16, State 1, Line 11  
  33. --Implicit conversion of varchar value to varchar cannot be performed because the collation of the value is unresolved due to a collation conflict.  
  1.  /*该查询是一个已经编写好的查询语句,只是根据需要我们做出了适当的调整。即新增了一个JOIN表Dim_UserId,然后将CASE子句中THEN后    
  2.  面跟的,原来为FPIDKey更换为FPID,ELSE后面的UserId更换为UserGUID。修改后的批处理中语法检查时并没有发现任何错误。执行时出现   
  3.  上述错误提示。从错误的提示来分析是因为排序冲突所致,因此查看新增的两个字段是否使用了相同的排序规则。下面是查看语句: */    
  1. SELECT o.name,o.object_id,c.name,c.column_id,c.collation_name   
  2. FROM sys.columns c  
  3.     JOIN sys.objects o  
  4.         ON c.object_id = o.object_id   
  5. WHERE o.object_id = OBJECT_ID('dbo.Dim_UserId')  
  6.     AND c.name = 'UserGUID'  
  7. UNION   
  8. SELECT o.name,o.object_id,c.name,c.column_id,c.collation_name   
  9. FROM sys.columns c  
  10.     JOIN sys.objects o  
  11.         ON c.object_id = o.object_id   
  12. WHERE o.object_id = OBJECT_ID('dbo.Agg_User_Archive')  
  13.     AND c.name = 'FPID'  
  14. /*      
  15. name               object_id      name     column_id   collation_name  
  16. ------------------ ----------- ---------- ----------- ----------------------  
  17. Agg_User_Archive   1613248802   FPID       28          Latin1_General_CS_AI  
  18. Dim_UserId         1234819461  UserGUID    2           Latin1_General_BIN  
  19. */      
  20.   
  21. --从查询结果中可以看出,原来是因为两个列使用的不同的排序规则,故在count运算时发生了错误。于是修改语句如下,问题解决。下面仅列出被修改过的语句。   
  1. COUNT(DISTINCT CASE WHEN au.UserId = 6264375 THEN au.FPID COLLATE DATABASE_DEFAULT   
  2.                 ELSE du.UserGUID  COLLATE DATABASE_DEFAULT END  
  3.       ) AS DistinctUsers  

以下列出Collate子句的语法: 
COLLATE { <collation_name> | database_default } 
<collation_name> :: =      { Windows_collation_name } | { SQL_collation_name }

几点注意事项: 
一、排序规则可以在以下几个级别指定: 
1.创建或更改数据库。 
2.创建或更改表列。 
3.投影表达式的排序规则。 
二、COLLATE 子句只能应用于 char、varchar、text、nchar、nvarchar 和 ntext 数据类型。

其它关于排序规则问题请参照本人的其它文章:SQL server 排序规则(COLLATE)
更多参考:http://msdn.microsoft.com/zh-cn/library/ms184391.aspx

 

http://blog.csdn.net/robinson_0612/article/details/5393619