Query.php 12 KB

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