Query.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think\db;
  13. use PDOStatement;
  14. use think\helper\Str;
  15. /**
  16. * PDO数据查询类
  17. */
  18. class Query extends BaseQuery
  19. {
  20. use concern\JoinAndViewQuery;
  21. use concern\ParamsBind;
  22. use concern\TableFieldInfo;
  23. /**
  24. * 表达式方式指定Field排序
  25. * @access public
  26. * @param string $field 排序字段
  27. * @param array $bind 参数绑定
  28. * @return $this
  29. */
  30. public function orderRaw(string $field, array $bind = [])
  31. {
  32. $this->options['order'][] = new Raw($field, $bind);
  33. return $this;
  34. }
  35. /**
  36. * 表达式方式指定查询字段
  37. * @access public
  38. * @param string $field 字段名
  39. * @return $this
  40. */
  41. public function fieldRaw(string $field)
  42. {
  43. $this->options['field'][] = new Raw($field);
  44. return $this;
  45. }
  46. /**
  47. * 指定Field排序 orderField('id',[1,2,3],'desc')
  48. * @access public
  49. * @param string $field 排序字段
  50. * @param array $values 排序值
  51. * @param string $order 排序 desc/asc
  52. * @return $this
  53. */
  54. public function orderField(string $field, array $values, string $order = '')
  55. {
  56. if (!empty($values)) {
  57. $values['sort'] = $order;
  58. $this->options['order'][$field] = $values;
  59. }
  60. return $this;
  61. }
  62. /**
  63. * 随机排序
  64. * @access public
  65. * @return $this
  66. */
  67. public function orderRand()
  68. {
  69. $this->options['order'][] = '[rand]';
  70. return $this;
  71. }
  72. /**
  73. * 使用表达式设置数据
  74. * @access public
  75. * @param string $field 字段名
  76. * @param string $value 字段值
  77. * @return $this
  78. */
  79. public function exp(string $field, string $value)
  80. {
  81. $this->options['data'][$field] = new Raw($value);
  82. return $this;
  83. }
  84. /**
  85. * 表达式方式指定当前操作的数据表
  86. * @access public
  87. * @param mixed $table 表名
  88. * @return $this
  89. */
  90. public function tableRaw(string $table)
  91. {
  92. $this->options['table'] = new Raw($table);
  93. return $this;
  94. }
  95. /**
  96. * 获取执行的SQL语句而不进行实际的查询
  97. * @access public
  98. * @param bool $fetch 是否返回sql
  99. * @return $this|Fetch
  100. */
  101. public function fetchSql(bool $fetch = true)
  102. {
  103. $this->options['fetch_sql'] = $fetch;
  104. if ($fetch) {
  105. return new Fetch($this);
  106. }
  107. return $this;
  108. }
  109. /**
  110. * 批处理执行SQL语句
  111. * 批处理的指令都认为是execute操作
  112. * @access public
  113. * @param array $sql SQL批处理指令
  114. * @return bool
  115. */
  116. public function batchQuery(array $sql = []): bool
  117. {
  118. return $this->connection->batchQuery($this, $sql);
  119. }
  120. /**
  121. * USING支持 用于多表删除
  122. * @access public
  123. * @param mixed $using USING
  124. * @return $this
  125. */
  126. public function using($using)
  127. {
  128. $this->options['using'] = $using;
  129. return $this;
  130. }
  131. /**
  132. * 存储过程调用
  133. * @access public
  134. * @param bool $procedure 是否为存储过程查询
  135. * @return $this
  136. */
  137. public function procedure(bool $procedure = true)
  138. {
  139. $this->options['procedure'] = $procedure;
  140. return $this;
  141. }
  142. /**
  143. * 指定group查询
  144. * @access public
  145. * @param string|array $group GROUP
  146. * @return $this
  147. */
  148. public function group($group)
  149. {
  150. $this->options['group'] = $group;
  151. return $this;
  152. }
  153. /**
  154. * 指定having查询
  155. * @access public
  156. * @param string $having having
  157. * @return $this
  158. */
  159. public function having(string $having)
  160. {
  161. $this->options['having'] = $having;
  162. return $this;
  163. }
  164. /**
  165. * 指定distinct查询
  166. * @access public
  167. * @param bool $distinct 是否唯一
  168. * @return $this
  169. */
  170. public function distinct(bool $distinct = true)
  171. {
  172. $this->options['distinct'] = $distinct;
  173. return $this;
  174. }
  175. /**
  176. * 指定强制索引
  177. * @access public
  178. * @param string $force 索引名称
  179. * @return $this
  180. */
  181. public function force(string $force)
  182. {
  183. $this->options['force'] = $force;
  184. return $this;
  185. }
  186. /**
  187. * 查询注释
  188. * @access public
  189. * @param string $comment 注释
  190. * @return $this
  191. */
  192. public function comment(string $comment)
  193. {
  194. $this->options['comment'] = $comment;
  195. return $this;
  196. }
  197. /**
  198. * 设置是否REPLACE
  199. * @access public
  200. * @param bool $replace 是否使用REPLACE写入数据
  201. * @return $this
  202. */
  203. public function replace(bool $replace = true)
  204. {
  205. $this->options['replace'] = $replace;
  206. return $this;
  207. }
  208. /**
  209. * 设置当前查询所在的分区
  210. * @access public
  211. * @param string|array $partition 分区名称
  212. * @return $this
  213. */
  214. public function partition($partition)
  215. {
  216. $this->options['partition'] = $partition;
  217. return $this;
  218. }
  219. /**
  220. * 设置DUPLICATE
  221. * @access public
  222. * @param array|string|Raw $duplicate DUPLICATE信息
  223. * @return $this
  224. */
  225. public function duplicate($duplicate)
  226. {
  227. $this->options['duplicate'] = $duplicate;
  228. return $this;
  229. }
  230. /**
  231. * 设置查询的额外参数
  232. * @access public
  233. * @param string $extra 额外信息
  234. * @return $this
  235. */
  236. public function extra(string $extra)
  237. {
  238. $this->options['extra'] = $extra;
  239. return $this;
  240. }
  241. /**
  242. * 创建子查询SQL
  243. * @access public
  244. * @param bool $sub 是否添加括号
  245. * @return string
  246. * @throws Exception
  247. */
  248. public function buildSql(bool $sub = true): string
  249. {
  250. return $sub ? '( ' . $this->fetchSql()->select() . ' )' : $this->fetchSql()->select();
  251. }
  252. /**
  253. * 获取当前数据表的主键
  254. * @access public
  255. * @return string|array
  256. */
  257. public function getPk()
  258. {
  259. if (empty($this->pk)) {
  260. $this->pk = $this->connection->getPk($this->getTable());
  261. }
  262. return $this->pk;
  263. }
  264. /**
  265. * 指定数据表自增主键
  266. * @access public
  267. * @param string $autoinc 自增键
  268. * @return $this
  269. */
  270. public function autoinc(string $autoinc)
  271. {
  272. $this->autoinc = $autoinc;
  273. return $this;
  274. }
  275. /**
  276. * 获取当前数据表的自增主键
  277. * @access public
  278. * @return string|null
  279. */
  280. public function getAutoInc()
  281. {
  282. $tableName = $this->getTable();
  283. if (empty($this->autoinc) && $tableName) {
  284. $this->autoinc = $this->connection->getAutoInc($tableName);
  285. }
  286. return $this->autoinc;
  287. }
  288. /**
  289. * 字段值增长
  290. * @access public
  291. * @param string $field 字段名
  292. * @param float $step 增长值
  293. * @return $this
  294. */
  295. public function inc(string $field, float $step = 1)
  296. {
  297. $this->options['data'][$field] = ['INC', $step];
  298. return $this;
  299. }
  300. /**
  301. * 字段值减少
  302. * @access public
  303. * @param string $field 字段名
  304. * @param float $step 增长值
  305. * @return $this
  306. */
  307. public function dec(string $field, float $step = 1)
  308. {
  309. $this->options['data'][$field] = ['DEC', $step];
  310. return $this;
  311. }
  312. /**
  313. * 获取当前的查询标识
  314. * @access public
  315. * @param mixed $data 要序列化的数据
  316. * @return string
  317. */
  318. public function getQueryGuid($data = null): string
  319. {
  320. return md5($this->getConfig('database') . serialize(var_export($data ?: $this->options, true)) . serialize($this->getBind(false)));
  321. }
  322. /**
  323. * 执行查询但只返回PDOStatement对象
  324. * @access public
  325. * @return PDOStatement
  326. */
  327. public function getPdo(): PDOStatement
  328. {
  329. return $this->connection->pdo($this);
  330. }
  331. /**
  332. * 使用游标查找记录
  333. * @access public
  334. * @param mixed $data 数据
  335. * @return \Generator
  336. */
  337. public function cursor($data = null)
  338. {
  339. if (!is_null($data)) {
  340. // 主键条件分析
  341. $this->parsePkWhere($data);
  342. }
  343. $this->options['data'] = $data;
  344. $connection = clone $this->connection;
  345. return $connection->cursor($this);
  346. }
  347. /**
  348. * 分批数据返回处理
  349. * @access public
  350. * @param integer $count 每次处理的数据数量
  351. * @param callable $callback 处理回调方法
  352. * @param string|array $column 分批处理的字段名
  353. * @param string $order 字段排序
  354. * @return bool
  355. * @throws Exception
  356. */
  357. public function chunk(int $count, callable $callback, $column = null, string $order = 'asc'): bool
  358. {
  359. $options = $this->getOptions();
  360. $column = $column ?: $this->getPk();
  361. if (isset($options['order'])) {
  362. unset($options['order']);
  363. }
  364. $bind = $this->bind;
  365. if (is_array($column)) {
  366. $times = 1;
  367. $query = $this->options($options)->page($times, $count);
  368. } else {
  369. $query = $this->options($options)->limit($count);
  370. if (strpos($column, '.')) {
  371. [$alias, $key] = explode('.', $column);
  372. } else {
  373. $key = $column;
  374. }
  375. }
  376. $resultSet = $query->order($column, $order)->select();
  377. while (count($resultSet) > 0) {
  378. if (false === call_user_func($callback, $resultSet)) {
  379. return false;
  380. }
  381. if (isset($times)) {
  382. $times++;
  383. $query = $this->options($options)->page($times, $count);
  384. } else {
  385. $end = $resultSet->pop();
  386. $lastId = is_array($end) ? $end[$key] : $end->getData($key);
  387. $query = $this->options($options)
  388. ->limit($count)
  389. ->where($column, 'asc' == strtolower($order) ? '>' : '<', $lastId);
  390. }
  391. $resultSet = $query->bind($bind)->order($column, $order)->select();
  392. }
  393. return true;
  394. }
  395. }