PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/PHPExcel/Calculation/Database.php

https://github.com/yuweijun/blog
PHP | 676 lines | 200 code | 48 blank | 428 comment | 22 complexity | 6199b2eee63647ec18c0f1652c9583dc MD5 | raw file
  1. <?php
  2. /** PHPExcel root directory */
  3. if (!defined('PHPEXCEL_ROOT')) {
  4. /**
  5. * @ignore
  6. */
  7. define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
  8. require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  9. }
  10. /**
  11. * PHPExcel_Calculation_Database
  12. *
  13. * Copyright (c) 2006 - 2015 PHPExcel
  14. *
  15. * This library is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU Lesser General Public
  17. * License as published by the Free Software Foundation; either
  18. * version 2.1 of the License, or (at your option) any later version.
  19. *
  20. * This library is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23. * Lesser General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Lesser General Public
  26. * License along with this library; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  28. *
  29. * @category PHPExcel
  30. * @package PHPExcel_Calculation
  31. * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  32. * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
  33. * @version ##VERSION##, ##DATE##
  34. */
  35. class PHPExcel_Calculation_Database
  36. {
  37. /**
  38. * fieldExtract
  39. *
  40. * Extracts the column ID to use for the data field.
  41. *
  42. * @access private
  43. * @param mixed[] $database The range of cells that makes up the list or database.
  44. * A database is a list of related data in which rows of related
  45. * information are records, and columns of data are fields. The
  46. * first row of the list contains labels for each column.
  47. * @param mixed $field Indicates which column is used in the function. Enter the
  48. * column label enclosed between double quotation marks, such as
  49. * "Age" or "Yield," or a number (without quotation marks) that
  50. * represents the position of the column within the list: 1 for
  51. * the first column, 2 for the second column, and so on.
  52. * @return string|NULL
  53. *
  54. */
  55. private static function fieldExtract($database, $field)
  56. {
  57. $field = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($field));
  58. $fieldNames = array_map('strtoupper', array_shift($database));
  59. if (is_numeric($field)) {
  60. $keys = array_keys($fieldNames);
  61. return $keys[$field-1];
  62. }
  63. $key = array_search($field, $fieldNames);
  64. return ($key) ? $key : null;
  65. }
  66. /**
  67. * filter
  68. *
  69. * Parses the selection criteria, extracts the database rows that match those criteria, and
  70. * returns that subset of rows.
  71. *
  72. * @access private
  73. * @param mixed[] $database The range of cells that makes up the list or database.
  74. * A database is a list of related data in which rows of related
  75. * information are records, and columns of data are fields. The
  76. * first row of the list contains labels for each column.
  77. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  78. * You can use any range for the criteria argument, as long as it
  79. * includes at least one column label and at least one cell below
  80. * the column label in which you specify a condition for the
  81. * column.
  82. * @return array of mixed
  83. *
  84. */
  85. private static function filter($database, $criteria)
  86. {
  87. $fieldNames = array_shift($database);
  88. $criteriaNames = array_shift($criteria);
  89. // Convert the criteria into a set of AND/OR conditions with [:placeholders]
  90. $testConditions = $testValues = array();
  91. $testConditionsCount = 0;
  92. foreach ($criteriaNames as $key => $criteriaName) {
  93. $testCondition = array();
  94. $testConditionCount = 0;
  95. foreach ($criteria as $row => $criterion) {
  96. if ($criterion[$key] > '') {
  97. $testCondition[] = '[:'.$criteriaName.']'.PHPExcel_Calculation_Functions::ifCondition($criterion[$key]);
  98. $testConditionCount++;
  99. }
  100. }
  101. if ($testConditionCount > 1) {
  102. $testConditions[] = 'OR(' . implode(',', $testCondition) . ')';
  103. $testConditionsCount++;
  104. } elseif ($testConditionCount == 1) {
  105. $testConditions[] = $testCondition[0];
  106. $testConditionsCount++;
  107. }
  108. }
  109. if ($testConditionsCount > 1) {
  110. $testConditionSet = 'AND(' . implode(',', $testConditions) . ')';
  111. } elseif ($testConditionsCount == 1) {
  112. $testConditionSet = $testConditions[0];
  113. }
  114. // Loop through each row of the database
  115. foreach ($database as $dataRow => $dataValues) {
  116. // Substitute actual values from the database row for our [:placeholders]
  117. $testConditionList = $testConditionSet;
  118. foreach ($criteriaNames as $key => $criteriaName) {
  119. $k = array_search($criteriaName, $fieldNames);
  120. if (isset($dataValues[$k])) {
  121. $dataValue = $dataValues[$k];
  122. $dataValue = (is_string($dataValue)) ? PHPExcel_Calculation::wrapResult(strtoupper($dataValue)) : $dataValue;
  123. $testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList);
  124. }
  125. }
  126. // evaluate the criteria against the row data
  127. $result = PHPExcel_Calculation::getInstance()->_calculateFormulaValue('='.$testConditionList);
  128. // If the row failed to meet the criteria, remove it from the database
  129. if (!$result) {
  130. unset($database[$dataRow]);
  131. }
  132. }
  133. return $database;
  134. }
  135. private static function getFilteredColumn($database, $field, $criteria)
  136. {
  137. // reduce the database to a set of rows that match all the criteria
  138. $database = self::filter($database, $criteria);
  139. // extract an array of values for the requested column
  140. $colData = array();
  141. foreach ($database as $row) {
  142. $colData[] = $row[$field];
  143. }
  144. return $colData;
  145. }
  146. /**
  147. * DAVERAGE
  148. *
  149. * Averages the values in a column of a list or database that match conditions you specify.
  150. *
  151. * Excel Function:
  152. * DAVERAGE(database,field,criteria)
  153. *
  154. * @access public
  155. * @category Database Functions
  156. * @param mixed[] $database The range of cells that makes up the list or database.
  157. * A database is a list of related data in which rows of related
  158. * information are records, and columns of data are fields. The
  159. * first row of the list contains labels for each column.
  160. * @param string|integer $field Indicates which column is used in the function. Enter the
  161. * column label enclosed between double quotation marks, such as
  162. * "Age" or "Yield," or a number (without quotation marks) that
  163. * represents the position of the column within the list: 1 for
  164. * the first column, 2 for the second column, and so on.
  165. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  166. * You can use any range for the criteria argument, as long as it
  167. * includes at least one column label and at least one cell below
  168. * the column label in which you specify a condition for the
  169. * column.
  170. * @return float
  171. *
  172. */
  173. public static function DAVERAGE($database, $field, $criteria)
  174. {
  175. $field = self::fieldExtract($database, $field);
  176. if (is_null($field)) {
  177. return null;
  178. }
  179. // Return
  180. return PHPExcel_Calculation_Statistical::AVERAGE(
  181. self::getFilteredColumn($database, $field, $criteria)
  182. );
  183. }
  184. /**
  185. * DCOUNT
  186. *
  187. * Counts the cells that contain numbers in a column of a list or database that match conditions
  188. * that you specify.
  189. *
  190. * Excel Function:
  191. * DCOUNT(database,[field],criteria)
  192. *
  193. * Excel Function:
  194. * DAVERAGE(database,field,criteria)
  195. *
  196. * @access public
  197. * @category Database Functions
  198. * @param mixed[] $database The range of cells that makes up the list or database.
  199. * A database is a list of related data in which rows of related
  200. * information are records, and columns of data are fields. The
  201. * first row of the list contains labels for each column.
  202. * @param string|integer $field Indicates which column is used in the function. Enter the
  203. * column label enclosed between double quotation marks, such as
  204. * "Age" or "Yield," or a number (without quotation marks) that
  205. * represents the position of the column within the list: 1 for
  206. * the first column, 2 for the second column, and so on.
  207. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  208. * You can use any range for the criteria argument, as long as it
  209. * includes at least one column label and at least one cell below
  210. * the column label in which you specify a condition for the
  211. * column.
  212. * @return integer
  213. *
  214. * @TODO The field argument is optional. If field is omitted, DCOUNT counts all records in the
  215. * database that match the criteria.
  216. *
  217. */
  218. public static function DCOUNT($database, $field, $criteria)
  219. {
  220. $field = self::fieldExtract($database, $field);
  221. if (is_null($field)) {
  222. return null;
  223. }
  224. // Return
  225. return PHPExcel_Calculation_Statistical::COUNT(
  226. self::getFilteredColumn($database, $field, $criteria)
  227. );
  228. }
  229. /**
  230. * DCOUNTA
  231. *
  232. * Counts the nonblank cells in a column of a list or database that match conditions that you specify.
  233. *
  234. * Excel Function:
  235. * DCOUNTA(database,[field],criteria)
  236. *
  237. * @access public
  238. * @category Database Functions
  239. * @param mixed[] $database The range of cells that makes up the list or database.
  240. * A database is a list of related data in which rows of related
  241. * information are records, and columns of data are fields. The
  242. * first row of the list contains labels for each column.
  243. * @param string|integer $field Indicates which column is used in the function. Enter the
  244. * column label enclosed between double quotation marks, such as
  245. * "Age" or "Yield," or a number (without quotation marks) that
  246. * represents the position of the column within the list: 1 for
  247. * the first column, 2 for the second column, and so on.
  248. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  249. * You can use any range for the criteria argument, as long as it
  250. * includes at least one column label and at least one cell below
  251. * the column label in which you specify a condition for the
  252. * column.
  253. * @return integer
  254. *
  255. * @TODO The field argument is optional. If field is omitted, DCOUNTA counts all records in the
  256. * database that match the criteria.
  257. *
  258. */
  259. public static function DCOUNTA($database, $field, $criteria)
  260. {
  261. $field = self::fieldExtract($database, $field);
  262. if (is_null($field)) {
  263. return null;
  264. }
  265. // reduce the database to a set of rows that match all the criteria
  266. $database = self::filter($database, $criteria);
  267. // extract an array of values for the requested column
  268. $colData = array();
  269. foreach ($database as $row) {
  270. $colData[] = $row[$field];
  271. }
  272. // Return
  273. return PHPExcel_Calculation_Statistical::COUNTA(
  274. self::getFilteredColumn($database, $field, $criteria)
  275. );
  276. }
  277. /**
  278. * DGET
  279. *
  280. * Extracts a single value from a column of a list or database that matches conditions that you
  281. * specify.
  282. *
  283. * Excel Function:
  284. * DGET(database,field,criteria)
  285. *
  286. * @access public
  287. * @category Database Functions
  288. * @param mixed[] $database The range of cells that makes up the list or database.
  289. * A database is a list of related data in which rows of related
  290. * information are records, and columns of data are fields. The
  291. * first row of the list contains labels for each column.
  292. * @param string|integer $field Indicates which column is used in the function. Enter the
  293. * column label enclosed between double quotation marks, such as
  294. * "Age" or "Yield," or a number (without quotation marks) that
  295. * represents the position of the column within the list: 1 for
  296. * the first column, 2 for the second column, and so on.
  297. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  298. * You can use any range for the criteria argument, as long as it
  299. * includes at least one column label and at least one cell below
  300. * the column label in which you specify a condition for the
  301. * column.
  302. * @return mixed
  303. *
  304. */
  305. public static function DGET($database, $field, $criteria)
  306. {
  307. $field = self::fieldExtract($database, $field);
  308. if (is_null($field)) {
  309. return null;
  310. }
  311. // Return
  312. $colData = self::getFilteredColumn($database, $field, $criteria);
  313. if (count($colData) > 1) {
  314. return PHPExcel_Calculation_Functions::NaN();
  315. }
  316. return $colData[0];
  317. }
  318. /**
  319. * DMAX
  320. *
  321. * Returns the largest number in a column of a list or database that matches conditions you that
  322. * specify.
  323. *
  324. * Excel Function:
  325. * DMAX(database,field,criteria)
  326. *
  327. * @access public
  328. * @category Database Functions
  329. * @param mixed[] $database The range of cells that makes up the list or database.
  330. * A database is a list of related data in which rows of related
  331. * information are records, and columns of data are fields. The
  332. * first row of the list contains labels for each column.
  333. * @param string|integer $field Indicates which column is used in the function. Enter the
  334. * column label enclosed between double quotation marks, such as
  335. * "Age" or "Yield," or a number (without quotation marks) that
  336. * represents the position of the column within the list: 1 for
  337. * the first column, 2 for the second column, and so on.
  338. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  339. * You can use any range for the criteria argument, as long as it
  340. * includes at least one column label and at least one cell below
  341. * the column label in which you specify a condition for the
  342. * column.
  343. * @return float
  344. *
  345. */
  346. public static function DMAX($database, $field, $criteria)
  347. {
  348. $field = self::fieldExtract($database, $field);
  349. if (is_null($field)) {
  350. return null;
  351. }
  352. // Return
  353. return PHPExcel_Calculation_Statistical::MAX(
  354. self::getFilteredColumn($database, $field, $criteria)
  355. );
  356. }
  357. /**
  358. * DMIN
  359. *
  360. * Returns the smallest number in a column of a list or database that matches conditions you that
  361. * specify.
  362. *
  363. * Excel Function:
  364. * DMIN(database,field,criteria)
  365. *
  366. * @access public
  367. * @category Database Functions
  368. * @param mixed[] $database The range of cells that makes up the list or database.
  369. * A database is a list of related data in which rows of related
  370. * information are records, and columns of data are fields. The
  371. * first row of the list contains labels for each column.
  372. * @param string|integer $field Indicates which column is used in the function. Enter the
  373. * column label enclosed between double quotation marks, such as
  374. * "Age" or "Yield," or a number (without quotation marks) that
  375. * represents the position of the column within the list: 1 for
  376. * the first column, 2 for the second column, and so on.
  377. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  378. * You can use any range for the criteria argument, as long as it
  379. * includes at least one column label and at least one cell below
  380. * the column label in which you specify a condition for the
  381. * column.
  382. * @return float
  383. *
  384. */
  385. public static function DMIN($database, $field, $criteria)
  386. {
  387. $field = self::fieldExtract($database, $field);
  388. if (is_null($field)) {
  389. return null;
  390. }
  391. // Return
  392. return PHPExcel_Calculation_Statistical::MIN(
  393. self::getFilteredColumn($database, $field, $criteria)
  394. );
  395. }
  396. /**
  397. * DPRODUCT
  398. *
  399. * Multiplies the values in a column of a list or database that match conditions that you specify.
  400. *
  401. * Excel Function:
  402. * DPRODUCT(database,field,criteria)
  403. *
  404. * @access public
  405. * @category Database Functions
  406. * @param mixed[] $database The range of cells that makes up the list or database.
  407. * A database is a list of related data in which rows of related
  408. * information are records, and columns of data are fields. The
  409. * first row of the list contains labels for each column.
  410. * @param string|integer $field Indicates which column is used in the function. Enter the
  411. * column label enclosed between double quotation marks, such as
  412. * "Age" or "Yield," or a number (without quotation marks) that
  413. * represents the position of the column within the list: 1 for
  414. * the first column, 2 for the second column, and so on.
  415. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  416. * You can use any range for the criteria argument, as long as it
  417. * includes at least one column label and at least one cell below
  418. * the column label in which you specify a condition for the
  419. * column.
  420. * @return float
  421. *
  422. */
  423. public static function DPRODUCT($database, $field, $criteria)
  424. {
  425. $field = self::fieldExtract($database, $field);
  426. if (is_null($field)) {
  427. return null;
  428. }
  429. // Return
  430. return PHPExcel_Calculation_MathTrig::PRODUCT(
  431. self::getFilteredColumn($database, $field, $criteria)
  432. );
  433. }
  434. /**
  435. * DSTDEV
  436. *
  437. * Estimates the standard deviation of a population based on a sample by using the numbers in a
  438. * column of a list or database that match conditions that you specify.
  439. *
  440. * Excel Function:
  441. * DSTDEV(database,field,criteria)
  442. *
  443. * @access public
  444. * @category Database Functions
  445. * @param mixed[] $database The range of cells that makes up the list or database.
  446. * A database is a list of related data in which rows of related
  447. * information are records, and columns of data are fields. The
  448. * first row of the list contains labels for each column.
  449. * @param string|integer $field Indicates which column is used in the function. Enter the
  450. * column label enclosed between double quotation marks, such as
  451. * "Age" or "Yield," or a number (without quotation marks) that
  452. * represents the position of the column within the list: 1 for
  453. * the first column, 2 for the second column, and so on.
  454. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  455. * You can use any range for the criteria argument, as long as it
  456. * includes at least one column label and at least one cell below
  457. * the column label in which you specify a condition for the
  458. * column.
  459. * @return float
  460. *
  461. */
  462. public static function DSTDEV($database, $field, $criteria)
  463. {
  464. $field = self::fieldExtract($database, $field);
  465. if (is_null($field)) {
  466. return null;
  467. }
  468. // Return
  469. return PHPExcel_Calculation_Statistical::STDEV(
  470. self::getFilteredColumn($database, $field, $criteria)
  471. );
  472. }
  473. /**
  474. * DSTDEVP
  475. *
  476. * Calculates the standard deviation of a population based on the entire population by using the
  477. * numbers in a column of a list or database that match conditions that you specify.
  478. *
  479. * Excel Function:
  480. * DSTDEVP(database,field,criteria)
  481. *
  482. * @access public
  483. * @category Database Functions
  484. * @param mixed[] $database The range of cells that makes up the list or database.
  485. * A database is a list of related data in which rows of related
  486. * information are records, and columns of data are fields. The
  487. * first row of the list contains labels for each column.
  488. * @param string|integer $field Indicates which column is used in the function. Enter the
  489. * column label enclosed between double quotation marks, such as
  490. * "Age" or "Yield," or a number (without quotation marks) that
  491. * represents the position of the column within the list: 1 for
  492. * the first column, 2 for the second column, and so on.
  493. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  494. * You can use any range for the criteria argument, as long as it
  495. * includes at least one column label and at least one cell below
  496. * the column label in which you specify a condition for the
  497. * column.
  498. * @return float
  499. *
  500. */
  501. public static function DSTDEVP($database, $field, $criteria)
  502. {
  503. $field = self::fieldExtract($database, $field);
  504. if (is_null($field)) {
  505. return null;
  506. }
  507. // Return
  508. return PHPExcel_Calculation_Statistical::STDEVP(
  509. self::getFilteredColumn($database, $field, $criteria)
  510. );
  511. }
  512. /**
  513. * DSUM
  514. *
  515. * Adds the numbers in a column of a list or database that match conditions that you specify.
  516. *
  517. * Excel Function:
  518. * DSUM(database,field,criteria)
  519. *
  520. * @access public
  521. * @category Database Functions
  522. * @param mixed[] $database The range of cells that makes up the list or database.
  523. * A database is a list of related data in which rows of related
  524. * information are records, and columns of data are fields. The
  525. * first row of the list contains labels for each column.
  526. * @param string|integer $field Indicates which column is used in the function. Enter the
  527. * column label enclosed between double quotation marks, such as
  528. * "Age" or "Yield," or a number (without quotation marks) that
  529. * represents the position of the column within the list: 1 for
  530. * the first column, 2 for the second column, and so on.
  531. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  532. * You can use any range for the criteria argument, as long as it
  533. * includes at least one column label and at least one cell below
  534. * the column label in which you specify a condition for the
  535. * column.
  536. * @return float
  537. *
  538. */
  539. public static function DSUM($database, $field, $criteria)
  540. {
  541. $field = self::fieldExtract($database, $field);
  542. if (is_null($field)) {
  543. return null;
  544. }
  545. // Return
  546. return PHPExcel_Calculation_MathTrig::SUM(
  547. self::getFilteredColumn($database, $field, $criteria)
  548. );
  549. }
  550. /**
  551. * DVAR
  552. *
  553. * Estimates the variance of a population based on a sample by using the numbers in a column
  554. * of a list or database that match conditions that you specify.
  555. *
  556. * Excel Function:
  557. * DVAR(database,field,criteria)
  558. *
  559. * @access public
  560. * @category Database Functions
  561. * @param mixed[] $database The range of cells that makes up the list or database.
  562. * A database is a list of related data in which rows of related
  563. * information are records, and columns of data are fields. The
  564. * first row of the list contains labels for each column.
  565. * @param string|integer $field Indicates which column is used in the function. Enter the
  566. * column label enclosed between double quotation marks, such as
  567. * "Age" or "Yield," or a number (without quotation marks) that
  568. * represents the position of the column within the list: 1 for
  569. * the first column, 2 for the second column, and so on.
  570. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  571. * You can use any range for the criteria argument, as long as it
  572. * includes at least one column label and at least one cell below
  573. * the column label in which you specify a condition for the
  574. * column.
  575. * @return float
  576. *
  577. */
  578. public static function DVAR($database, $field, $criteria)
  579. {
  580. $field = self::fieldExtract($database, $field);
  581. if (is_null($field)) {
  582. return null;
  583. }
  584. // Return
  585. return PHPExcel_Calculation_Statistical::VARFunc(
  586. self::getFilteredColumn($database, $field, $criteria)
  587. );
  588. }
  589. /**
  590. * DVARP
  591. *
  592. * Calculates the variance of a population based on the entire population by using the numbers
  593. * in a column of a list or database that match conditions that you specify.
  594. *
  595. * Excel Function:
  596. * DVARP(database,field,criteria)
  597. *
  598. * @access public
  599. * @category Database Functions
  600. * @param mixed[] $database The range of cells that makes up the list or database.
  601. * A database is a list of related data in which rows of related
  602. * information are records, and columns of data are fields. The
  603. * first row of the list contains labels for each column.
  604. * @param string|integer $field Indicates which column is used in the function. Enter the
  605. * column label enclosed between double quotation marks, such as
  606. * "Age" or "Yield," or a number (without quotation marks) that
  607. * represents the position of the column within the list: 1 for
  608. * the first column, 2 for the second column, and so on.
  609. * @param mixed[] $criteria The range of cells that contains the conditions you specify.
  610. * You can use any range for the criteria argument, as long as it
  611. * includes at least one column label and at least one cell below
  612. * the column label in which you specify a condition for the
  613. * column.
  614. * @return float
  615. *
  616. */
  617. public static function DVARP($database, $field, $criteria)
  618. {
  619. $field = self::fieldExtract($database, $field);
  620. if (is_null($field)) {
  621. return null;
  622. }
  623. // Return
  624. return PHPExcel_Calculation_Statistical::VARP(
  625. self::getFilteredColumn($database, $field, $criteria)
  626. );
  627. }
  628. }