李洪强iOS开发之-环信05_EaseUI 使用指南

EaseUI 使用指南


简介

EaseUI 封装了 IM 功能常用的控件(如聊天会话、会话列表、联系人列表)。旨在帮助开发者快速集成环信 SDK。

源码地址:

快速集成

第 1 步:集成 EaseUI 前,首先需要集成环信 iOS SDK,参考:集成文档

第 2 步:参考ChatDemo3.0 导入的方式,直接将EaseUI拖入已经集成SDK的项目中

初始化

第 1 步:引入相关头文件 #import “EaseUI.h”。

第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[EaseSDKHelper shareHelper] easemobApplication:application
didFinishLaunchingWithOptions:launchOptions
appkey:@"douser#istore"
apnsCertName:@"istore_dev"
otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];
return YES;
}

聊天会话

创建聊天会话、传递用户或群 ID 和会话类型(EMConversationType)。

EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"8001" conversationType:EMConversationTypeChat];

聊天会话功能扩展

EaseUI 提供现成的聊天会话 ViewController,可以通过继承 EaseMessageViewController 方式(参考 ChatDemo-UI3.0 中 ChatViewController)实现对聊天会话的扩展。

也可以直接使用 EaseMessageViewController,通过 EaseMessageViewControllerDelegate 和 EaseMessageViewControllerDataSource 两个协议实现对 EaseMessageViewController 的扩展。

实现自定义聊天样式

EaseMessageViewControllerDelegate

获取自定义消息 cell,根据 messageModel,用户自己判断是否显示自定义消息 cell。如果返回 nil 会显示默认;如果返回 cell 会显示用户自定义消息cell。

/*!
@method
@brief 获取消息自定义cell
@discussion 用户根据messageModel判断是否显示自定义cell。返回nil显示默认cell,否则显示用户自定义cell
@param tableView 当前消息视图的tableView
@param messageModel 消息模型
@result 返回用户自定义cell
*/
- (UITableViewCell *)messageViewController:(UITableView *)tableView
cellForMessageModel:(id<IMessageModel>)messageModel;
 
/*!
@method
@brief 获取消息cell高度
@discussion 用户根据messageModel判断,是否自定义显示cell的高度
@param viewController 当前消息视图
@param messageModel 消息模型
@param cellWidth 视图宽度
@result 返回用户自定义cell
*/
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
heightForMessageModel:(id<IMessageModel>)messageModel
withCellWidth:(CGFloat)cellWidth;
 
//具体创建自定义Cell的样例:
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model
{
//样例为如果消息是文本消息显示用户自定义cell
if (model.bodyType == eMessageBodyType_Text) {
NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
//CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
CustomMessageCell *cell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.model = model;
return cell;
}
return nil;
}
 
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
heightForMessageModel:(id<IMessageModel>)messageModel
withCellWidth:(CGFloat)cellWidth
{
//样例为如果消息是文本消息使用用户自定义cell的高度
if (messageModel.bodyType == EMMessageBodyTypeText) {
//CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
return [CustomMessageCell cellHeightWithModel:messageModel];
}
return 0.f;
}

通过自定义cell展示动态表情的效果图:

选中消息的回调

/*!
@method
@brief 选中消息的回调
@discussion 用户根据messageModel判断,是否自定义处理消息选中时间。返回YES为自定义处理,返回NO为默认处理
@param viewController 当前消息视图
@param messageModel 消息模型
@result 是否采用自定义处理
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didSelectMessageModel:(id<IMessageModel>)messageModel;
 
//选中消息回调的样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didSelectMessageModel:(id<IMessageModel>)messageModel
{
BOOL flag = NO;
//样例为如果消息是文件消息用户自定义处理选中逻辑
switch (messageModel.bodyType) {
case EMMessageBodyTypeImage:
case EMMessageBodyTypeLocation:
case EMMessageBodyTypeVideo:
case EMMessageBodyTypeVoice:
break;
case EMMessageBodyTypeFile:
{
flag = YES;
NSLog(@"用户自定义实现");
}
break;
default:
break;
}
return flag;
}

用户选中头像的回调

/*!
@method
@brief 点击消息头像
@discussion 获取用户点击头像回调
@param viewController 当前消息视图
@param messageModel 消息模型
@result
*/
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectAvatarMessageModel:(id<IMessageModel>)messageModel;
 
//获取用户点击头像回调的样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectAvatarMessageModel:(id<IMessageModel>)messageModel
{
//UserProfileViewController用户自定义的个人信息视图
//样例的逻辑是选中消息头像后,进入该消息发送者的个人信息
UserProfileViewController *userprofile = [[UserProfileViewController alloc] initWithUsername:messageModel.message.from];
[self.navigationController pushViewController:userprofile animated:YES];
}

录音按钮状态的回调

/*!
@method
@brief 底部录音功能按钮状态回调
@discussion 获取底部录音功能按钮状态回调,根据EaseRecordViewType,用户自定义处理UI的逻辑
@param viewController 当前消息视图
@param recordView 录音视图
@param type 录音按钮当前状态
@result
*/
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectRecordView:(UIView *)recordView
withEvenType:(EaseRecordViewType)type;
 
//录音按钮状态的回调样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectRecordView:(UIView *)recordView
withEvenType:(EaseRecordViewType)type
{
/*
EaseRecordViewTypeTouchDown,//录音按钮按下
EaseRecordViewTypeTouchUpInside,//手指在录音按钮内部时离开
EaseRecordViewTypeTouchUpOutside,//手指在录音按钮外部时离开
EaseRecordViewTypeDragInside,//手指移动到录音按钮内部
EaseRecordViewTypeDragOutside,//手指移动到录音按钮外部
*/
//根据type类型,用户自定义处理UI的逻辑
switch (type) {
case EaseRecordViewTypeTouchDown:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchDown];
}
}
break;
case EaseRecordViewTypeTouchUpInside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchUpInside];
}
[self.recordView removeFromSuperview];
}
break;
case EaseRecordViewTypeTouchUpOutside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonTouchUpOutside];
}
[self.recordView removeFromSuperview];
}
break;
case EaseRecordViewTypeDragInside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonDragInside];
}
}
break;
case EaseRecordViewTypeDragOutside:
{
if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
[(EaseRecordView *)self.recordView recordButtonDragOutside];
}
}
break;
default:
break;
}
}

EaseMessageViewControllerDataSource

用户判断消息是否允许长按,返回布尔值;如果用户允许长按,此方法为通知用户触发长按手势,返回布尔值,如果返回 NO 默认方式处理,返回 YES 采用用户自定义的处理方式。

/*!
@method
@brief 是否允许长按
@discussion 获取是否允许长按的回调,默认是NO
@param viewController 当前消息视图
@param indexPath 长按消息对应的indexPath
@result
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
canLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
 
/*!
@method
@brief 触发长按手势
@discussion 获取触发长按手势的回调,默认是NO
@param viewController 当前消息视图
@param indexPath 长按消息对应的indexPath
@result
*/
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
 
//长按收拾回调样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
canLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
//样例给出的逻辑是所有cell都允许长按
return YES;
}
 
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
//样例给出的逻辑是长按cell之后显示menu视图
id object = [self.dataArray objectAtIndex:indexPath.row];
if (![object isKindOfClass:[NSString class]]) {
EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell becomeFirstResponder];
self.menuIndexPath = indexPath;
[self _showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
}
return YES;
}

Demo3.0实现的消息长按效果演示:

将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像。

/*!
@method
@brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
@discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
@param viewController 当前消息视图
@param EMMessage 聊天消息对象类型
@result 返回<IMessageModel>协议的类型
*/
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message;
 
//具体样例:
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message
{
//用户可以根据自己的用户体系,根据message设置用户昵称和头像
id<IMessageModel> model = nil;
model = [[EaseMessageModel alloc] initWithMessage:message];
model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
model.avatarURLPath = @"";//头像网络地址
model.nickname = @"昵称";//用户昵称
return model;
}

聊天会话页面头像和昵称的效果演示:

聊天会话样式自定义

聊天样式的自定义需要在 EaseMessageViewController 中 viewDidload 结束前设置。

//@property中带有UI_APPEARANCE_SELECTOR,都可以通过set的形式设置样式,具体可以参考EaseBaseMessageCell.h,EaseMessageCell.h
 
[[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage imageNamed:@"chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];//设置发送气泡
[[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];//设置接收气泡
 
[[EaseBaseMessageCell appearance] setAvatarSize:40.f];//设置头像大小
[[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f];//设置头像圆角

消息发送

EaseSDKHelper 封装了发送消息的方法。

具体发送消息样例:

/*
EMChatTypeChat 单聊消息
EMChatTypeGroupChat 群聊消息
EMChatTypeChatRoom 聊天室消息
*/
 
//发送文字消息
EMMessage *message = [EaseSDKHelper sendTextMessage:@"要发送的消息"
to:@"6001"//接收方
messageType:EMChatTypeChat//消息类型
messageExt:nil]; //扩展信息
//发送位置消息
EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:35.1//经度
longitude:35.1//纬度
address:"地址"
to:@"6001"//接收方
messageType:EMChatTypeChat//消息类型
messageExt:nil];//扩展信息
 
//发送图片消息
EMMessage *message = [EaseSDKHelper sendImageMessageWithImageData:imageData//发送的图片数据NSData
to:@"6001"//接收方
messageType:EMChatTypeChat//消息类型
messageExt:nil];//扩展信息
 
//发送音频消息
EMMessage *message = [EaseSDKHelper sendVoiceMessageWithLocalPath:localPath//音频本地地址
duration:duration//语音的时长,单位是秒
to:@"6001"//接收方
messageType:EMChatTypeChat//消息类型
messageExt:nil];//扩展信息
 
//发送视频文件消息
EMMessage *message = [EaseSDKHelper sendVideoMessageWithURL:url//发送的视频地址
to:@"6001"//接收方
messageType:EMChatTypeChat//消息类型
messageExt:nil];//扩展信息
 
//发送构造成功的消息
[[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {
 
}];

会话列表

 

会话列表初始化

EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] init];

会话列表扩展

EaseConversationListViewControllerDataSource

用户根据 conversationModel 实现,实现自定义会话中最后一条消息文案的显示内容。

/*!
@method
@brief 获取最后一条消息显示的内容
@discussion 用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result 返回用户最后一条消息显示的内容
*/
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel;
 
 
/*!
@method
@brief 获取最后一条消息显示的时间
@discussion 用户可以根据conversationModel,自定义实现会话列表中时间文案的显示内容
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result 返回用户最后一条消息时间的显示文案
*/
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel;
 
//最后一条消息展示内容样例
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel
{
NSString *latestMessageTitle = @"";
EMMessage *lastMessage = [conversationModel.conversation latestMessage];
if (lastMessage) {
EMMessageBody *messageBody = lastMessage.body;
switch (messageBody.type) {
case EMMessageBodyTypeImage:{
latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
} break;
case EMMessageBodyTypeText:{
// 表情映射。
NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
latestMessageTitle = didReceiveText;
if ([lastMessage.ext objectForKey:MESSAGE_ATTR_IS_BIG_EXPRESSION]) {
latestMessageTitle = @"[动画表情]";
}
} break;
case EMMessageBodyTypeVoice:{
latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
} break;
case EMMessageBodyTypeLocation: {
latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
} break;
case EMMessageBodyTypeVideo: {
latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
} break;
case EMMessageBodyTypeFile: {
latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
} break;
default: {
} break;
}
}
 
return latestMessageTitle;
}
 
//最后一条消息展示时间样例
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel
{
NSString *latestMessageTime = @"";
EMMessage *lastMessage = [conversationModel.conversation latestMessage];;
if (lastMessage) {
latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
}
return latestMessageTime;
}

会话列表最后一条消息和时间显示的效果演示:

EaseConversationListViewControllerDelegate

点击会话列表用户可以根据 conversationModel 自定义处理逻辑。

/*!
@method
@brief 获取点击会话列表的回调
@discussion 获取点击会话列表的回调后,点击会话列表用户可以根据conversationModel自定义处理逻辑
@param conversationListViewController 当前会话列表视图
@param IConversationModel 会话模型
@result
*/
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
didSelectConversationModel:(id<IConversationModel>)conversationModel;
 
//会话列表点击的回调样例
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
didSelectConversationModel:(id<IConversationModel>)conversationModel
{
//样例展示为根据conversationModel,进入不同的会话ViewController
if (conversationModel) {
EMConversation *conversation = conversationModel.conversation;
if (conversation) {
if ([[RobotManager sharedInstance] isRobotWithUsername:conversation.conversationId]) {
RobotChatViewController *chatController = [[RobotChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
chatController.title = [[RobotManager sharedInstance] getRobotNickWithUsername:conversation.conversationId];
[self.navigationController pushViewController:chatController animated:YES];
} else {
ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
chatController.title = conversationModel.title;
[self.navigationController pushViewController:chatController animated:YES];
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"setupUnreadMessageCount" object:nil];
[self.tableView reloadData];
}
}

联系人列表

 

联系人列表初始化

EaseUsersListViewController *listViewController = [[EaseUsersListViewController alloc] init];

联系人列表扩展

需要实现 EMUserListViewControllerDataSource。

根据 buddy 获取用户自定信息,联系人列表里展示昵称和头像。

/*!
@method
@brief 获取用户模型
@discussion 根据buddy获取用户自定信息,联系人列表里展示昵称和头像
@param userListViewController 当前联系人视图
@param buddy 好友的信息描述类
@result 返回用户模型
*/
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
modelForBuddy:(NSString *)buddy;
 
//联系人列表扩展样例
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
modelForBuddy:(NSString *)buddy
{
//用户可以根据自己的用户体系,根据buddy设置用户昵称和头像
id<IUserModel> model = nil;
model = [[EaseUserModel alloc] initWithBuddy:buddy];
model.avatarURLPath = @"";//头像网络地址
model.nickname = @"昵称";//用户昵称
return model;
}

联系人列表头像和昵称的效果演示:

李洪强iOS开发之-环信05_EaseUI 使用指南的更多相关文章

  1. 李洪强iOS开发之-环信04_消息

    李洪强iOS开发之-环信04_消息 消息:IM 交互实体,在 SDK 中对应的类型是 EMMessage.EMMessage 由 EMMessageBody 组成. 构造消息   构造文字消息 EMT ...

  2. 李洪强iOS开发之-环信03_集成 SDK 基础功能

    李洪强iOS开发之-环信03_集成 SDK 基础功能 集成 SDK 基础功能 在您阅读此文档时,我们假定您已经具备了基础的 iOS 应用开发经验,并能够理解相关基础概念. SDK 同步/异步方法区分 ...

  3. 李洪强iOS开发之-环信02.2_环信官网下载环信 SDK

    李洪强iOS开发之-环信02.2_环信官网下载环信 SDK 移动客服即时通讯云 iOS SDK 当前版本:V3.1.4 2016-07-08 [ 版本历史 ] | 开发指南 | 知识库 | Demo源 ...

  4. 李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档

    李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档 SDK 2.x 至 3.0 升级指南 环信 SDK 3.0 升级文档 3.0 中的核心类为 EMClient 类,通过 EMCl ...

  5. 李洪强iOS开发之-环信02_iOS SDK 介绍及导入

    李洪强iOS开发之-环信02_iOS SDK 介绍及导入 iOS SDK 介绍及导入 iOS SDK 介绍 环信 SDK 为用户开发 IM 相关的应用提供的一套完善的开发框架.包括以下几个部分: SD ...

  6. 李洪强iOS开发之-环信01_iOS SDK 前的准备工作

    李洪强iOS开发之-环信01_iOS SDK 前的准备工作 1.1_注册环信开发者账号并创建后台应用 详细步骤:  注册并创建应用 注册环信开发者账号 第 1 步:在环信官网上点击“即时通讯云”,并点 ...

  7. 李洪强iOS开发之-环信02.3_具体接口讲解 - Apple Docs

    http://www.easemob.com/apidoc/ios/chat3.0/annotated.html Apple Docs.

  8. 李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入

    李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入 01 - 直接在项目中导入SDK和一些静态库 这个时候,没有错误的编译没有错误的话,就说明SDK已经配置成功 还有一种方法是用cocoap ...

  9. 李洪强iOS开发本人集成环信的经验总结_03_注册

    李洪强iOS开发本人集成环信的经验总结_03_注册 环信一共提供了三种注册的方法:  01 同步注册:  02 异步注册:  03 - 使用代理回调进行注册,但是3.0没有了,3.0之前有  调用注册 ...

随机推荐

  1. ant design 树形组件怎么使用

    getDefaultProps doesn't work with ES6 syntax; warning is not helpful 解决后: 参考地址:https://github.com/fa ...

  2. ant design 自定义表单验证大全

     需求是 账号名可以是手机号也可以是邮箱 要做手机号和邮箱的验证,官网的那个验证规则不匹配  怎么自定义验证规则?  一:组件部分 <Form horizontal> <Row gu ...

  3. session的介绍与简单使用

    cookie由浏览器带着,容易被篡改因为cookie很容易被篡改,所以cookie用来记住用户名,记住浏览历史等安全性要求不高的地方可以用sessin技术session技术将信息存入服务器,然后再给客 ...

  4. JAXB - Annotations, Type Adapters: XmlJavaTypeAdapter

    For some Java container types JAXB has no built-in mapping to an XML structure. Also, you may want t ...

  5. spark stream初探

    spark带了一个NetworkWordCount测试程序,用以统计来自某TCP连接的单词输入: /usr/local/spark/bin/run-example streaming.NetworkW ...

  6. Spring的servlet context和application context

    Spring lets you define multiple contexts in a parent-child hierarchy. The applicationContext.xml def ...

  7. Android之Http网络编程(二)

    上一篇文章简单的介绍了Android中http的两种通信方式,并且分别用获取百度网页做了实例.但是在实际应用中,更多的是客户端通过请求的参数来实现在服务端的具体操作,并最终返回数据给客户端.因为我们不 ...

  8. Cordova+angularjs+ionic+vs2015开发(四)

    欢迎加群学习:457351423 这里有4000多部学习视频,涵盖各种技术,有需要的欢迎进群学习! 一.布局 Ionic模板提供了一个侧边栏菜单示例项目和标签选项卡示例项目.本案例将两个布局进行结合, ...

  9. SQL Server 2012 中 Update FROM子句

    首先说明一下需求以及环境 创建Table1以及Table2两张表,并插入一下数据 USE AdventureWorks2012; GO IF OBJECT_ID ('dbo.Table1', 'U') ...

  10. 关于sql row_number,rank,dense_rank,ntile函数

    row_number排序最好用它,它依次排名,不出现相同名次,如:1,2,3,4,5 rank出现相同排名,且跳过相同的排名号排下一名,如:1,1,3,4,5, dense_rank出现相同排名,不跳 ...