BUG:Model类的select方法默认只返回1条记录

TP的手册中写的是select方法返回的是全部的记录,但我在实际操作中,返回的只有1条记录,我们再次进行源码的分析。

(1)Action中的代码如下:

  1. $operaInfo = new Model("tbloperainfo");
  2. $list = $operaInfo->select();

(2)根据代码我们进入Model类的select方法,在select方法中又调用了Db类的select方法:

  1. $resultSet = $this->db->select($options);

(3)select方法中有如下的代码片段,对查询的sql进行了处理:

  1. $sql   = str_replace(
  2. array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'),
  3. array(
  4. $this->parseTable($options['table']),
  5. $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
  6. $this->parseField(isset($options['field'])?$options['field']:'*'),
  7. $this->parseJoin(isset($options['join'])?$options['join']:''),
  8. $this->parseWhere(isset($options['where'])?$options['where']:''),
  9. $this->parseGroup(isset($options['group'])?$options['group']:''),
  10. $this->parseHaving(isset($options['having'])?$options['having']:''),
  11. $this->parseOrder(isset($options['order'])?$options['order']:''),
  12. $this->parseLimit(isset($options['limit'])?$options['limit']:'')
  13. ),$this->selectSql);
  14. $sql   .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
  15. return $this->query($sql);

在处理的时候调用了parseLimit方法,由于面向对象的多态性,这个方法应该是在DbMssql中的parseLimit方法。我们看下该方法的参数:isset($options['limit'])?$options['limit']:'' 这个表达式结果应该为空字符串'',因为我们在调用Model类的select方法的时候没有传任何参数。

我们进入DbMssql看下代码如下:

  1. public function parseLimit($limit) {
  2. if(empty($limit)) $limit=1;
  3. $limit  =   explode(',',$limit);
  4. if(count($limit)>1)
  5. $limitStr   =   '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
  6. else
  7. $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
  8. return $limitStr;
  9. }

(4)在parseLimit方法中,第一步将$limit赋值为1;第二部将$limit拆分为数组;第三部判断数组的元素个数后执行了如下的代码:

$limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";

在这里我们可以看出$limitStr的具体值为:'(T1.ROW_NUMBER BETWEEN 1 AND 1)'

好,我们继续跟踪源码。

(5)第3步对$selectSql处理后,调用了DbMssql类的query方法,在该方法中又调用了getAll方法将查询的结果存入$result数组,紧接着将$result一层层返回。

(6)好,到此为止执行流程已经全部结束。我们看下具体执行的SQL,如下:

  1. SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE (T1.ROW_NUMBER BETWEEN 1 AND 1)

看下执行的SQL,发现引起这个BUG的原因就是: (T1.ROW_NUMBER BETWEEN 1 AND 1) 这个SQL片段。

(7)原因找到了,该如何处理呢?

我们肯定是在DbMssql类的parseLimit方法下手,因为我们需要查询所有的记录,因此该方法返回的值最好是为 '' 。我们将parseLimit方法的第一行代码修改为如下的代码:

  1. if(emptyempty($limit)) {
  2. return $limit;
  3. }

就是如果$limit为空,直接返回。修改后刷新下页面发现报错了,看了执行的SQL如下:

  1. SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER ( ORDER BY agentid) AS ROW_NUMBER FROM (SELECT * FROM tblagentinfo) AS thinkphp) AS T1 WHERE

发现SQL到WHERE关键字就没了,我们看下DbMssql中$selectSql的定义:

  1. protected $selectSql  =     'SELECT T1.* FROM (SELECT ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER, thinkphp.* FROM (SELECT %DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 WHERE %LIMIT%'

再结合parseLimit方法中的代码,具体处理方法如下:

1.将SQL中的WHERE删掉

2.在parseLimit中将代码修改如下:

  1. if(count($limit)>1)
  2. $limitStr    =   ' WHERE (T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
  3. else
  4. $limitStr = ' WHERE (T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";

即是将WHERE直接放到$limitStr中,这样就OK了。

转载于:https://blog.51cto.com/shane/778063

(二)关于ThinkPHP2.1版本操作MSSQL类的BUG--selec查询只得出1条记录相关推荐

  1. discuz mysql类_Discuz X2二次开发之数据库操作 DB类

    Discuz X2的数据库操作类主要包括以下几个: DB::result_first 返回SQL查询的唯一字段的唯一值,查询结果是字符 DB::fetch_first 返回SQL查询的多个字段的值,查 ...

  2. MSSQL分组取后每一组的最新一条记录

    数据库中二张表,用户表和奖金记录表,奖金记录表中一个用户有多条信息,有一个生效时间,现在要查询: 奖金生效时间在三天前,每个用户取最新一条奖金记录,且用户末锁定 以前用的方法是直接写在C#代码中的: ...

  3. Mysql数据库基本知识二:表的基础操作

    =================================[建表]============================== 分三部分: 1.指定表名 2.定义列(),列名 数据类型 约束 ...

  4. php实现分页mssql,PHP操作mssql数据库类,含分页类[分页类原创]

    /** * PHP操作mssql数据库类,含分页类 * Enter description here ... * @author aboc 9986584 2011-04-09 * */ class ...

  5. Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令

    Linux常用基本命令详解(一) Linux常用基本命令详解(二)-------磁盘分区和磁盘管理类命令 Linux常用基本命令详解(三) 1.磁盘分区 磁盘分区(系统分区)是使用分区编辑器(part ...

  6. 新酷卡 mysql接口_新酷卡M池二次开发模块数据库操作版

    有大神发了一个soket方式的,尝试继承到模块后发现soket不太适合放到易模块类内, 客户组件不支持放在类内,必须放在界面上,传入赋值类内客户变量,收到数据事件也没办法放在类内,放弃 远程服务支持库 ...

  7. HBase学习之路(二):Java客户端的CRUD操作详讲

    内容简介 一.概述 二.操作前的准备 三.put操作 1.单行put方法 2.使用Put列表 四.get操作 1.单行get方法 2.使用Get列表 五.delete操作 1.单行delete方法 2 ...

  8. VSTO Office二次开发PPTRibbonX命令操作及对象添加

    VSTO Office二次开发PPTRibbonX命令操作及对象添加 本篇分享对于Power Point中一些命令的操作和对于一些比较常用对象.特殊对象的添加功能. 对于Power Point命令操作 ...

  9. PHP数据库操作分页类

    MySQL数据库操作类: 1 <?php 2 class mysql { 3 private $db_host; //数据库主机 4 private $db_user; //数据库用户名 5 p ...

  10. 封装SQLDMO操作的类

    封装SQLDMO操作的类,能完成常用的SQL Server 2000管理工作. 使用前请添加 "Microsoft SQLDMO Object Library" COM 引用. 有 ...

最新文章

  1. ORA-12514 监听程序当前无法识别连接描述符中的服务
  2. python参考手册--第8章
  3. UDP千兆以太网FPGA_verilog实现(四、代码前期准备-UDP和IP协议构建)
  4. 听说,高手都用记事本写C语言代码?
  5. 程序员接私活的几个平台
  6. CPU负载均衡之EAS
  7. 三维点云配准 matlab,一种基于保局PCA的三维点云配准方法与流程
  8. BT5R3安装及汉化
  9. MAX30102 血氧调试笔记
  10. 颜色名称及色样表(HTML版)
  11. 【Analytics Kit】【FAQ】集成华为分析服务问题集合 SDK初始化失败/应用调试界面没有数据/常见错误提示
  12. 微信存储服务器,微信缓存指的是什么?
  13. 计算机管理下的打印机参数设置,提高办公效率 11种方法设置打印参数
  14. 借势氢能源发展热潮,重塑股份持续加速行业布局
  15. 2015062602 - 星际迷航.红杉书评
  16. CDH安装指南——酒仙网技术
  17. 母亲节板报图片计算机方案,母亲节电子手抄报图片大全
  18. 冲压模具中的回弹解决办法
  19. Java进阶学习第八天——WEB入门
  20. 支付宝APP支付申请

热门文章

  1. 认识以及安装redis
  2. Dynamics 365 Online-Unified User Interface
  3. (最短路)17bupt新生赛——F. ch追妹
  4. 自定义Angular服务
  5. Java 反射机制浅析
  6. .net System.IO之Stream的使用详解
  7. 24点游戏算法python_24点游戏算法
  8. 算法 判断多个点是否在同一圆周线上_广州灵活计费自动出盘机技术方案大盘点...
  9. android can为啥能发收不到数据_大数据显示:报读MBA已是未来竞争力提升的必然趋势...
  10. Nginx服务器中的Socket切分,需要的朋友可以参考下