Refactor the Excel Database functions; and rewrite the query building (#1871)
* Refactor the Excel Database functions; and rewrite the query building to fix a bug with complex multi-criteria queries that involve both AND and OR conditions * Fix handling for empty cells and NULL values in searches * Expand unit tests; and add TODOs for dates, percentages, and wildcard text comparisons
This commit is contained in:
parent
1318b90330
commit
3764f30354
|
|
@ -769,7 +769,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DAVERAGE' => [
|
'DAVERAGE' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DAVERAGE'],
|
'functionCall' => [Database\DAverage::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DAY' => [
|
'DAY' => [
|
||||||
|
|
@ -799,12 +799,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DCOUNT' => [
|
'DCOUNT' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DCOUNT'],
|
'functionCall' => [Database\DCount::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DCOUNTA' => [
|
'DCOUNTA' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DCOUNTA'],
|
'functionCall' => [Database\DCountA::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DDB' => [
|
'DDB' => [
|
||||||
|
|
@ -849,7 +849,7 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DGET' => [
|
'DGET' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DGET'],
|
'functionCall' => [Database\DGet::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DISC' => [
|
'DISC' => [
|
||||||
|
|
@ -859,12 +859,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DMAX' => [
|
'DMAX' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DMAX'],
|
'functionCall' => [Database\DMax::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DMIN' => [
|
'DMIN' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DMIN'],
|
'functionCall' => [Database\DMin::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DOLLAR' => [
|
'DOLLAR' => [
|
||||||
|
|
@ -884,22 +884,22 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DPRODUCT' => [
|
'DPRODUCT' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DPRODUCT'],
|
'functionCall' => [Database\DProduct::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DSTDEV' => [
|
'DSTDEV' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DSTDEV'],
|
'functionCall' => [Database\DStDev::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DSTDEVP' => [
|
'DSTDEVP' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DSTDEVP'],
|
'functionCall' => [Database\DStDevP::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DSUM' => [
|
'DSUM' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DSUM'],
|
'functionCall' => [Database\DSum::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DURATION' => [
|
'DURATION' => [
|
||||||
|
|
@ -909,12 +909,12 @@ class Calculation
|
||||||
],
|
],
|
||||||
'DVAR' => [
|
'DVAR' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DVAR'],
|
'functionCall' => [Database\DVar::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'DVARP' => [
|
'DVARP' => [
|
||||||
'category' => Category::CATEGORY_DATABASE,
|
'category' => Category::CATEGORY_DATABASE,
|
||||||
'functionCall' => [Database::class, 'DVARP'],
|
'functionCall' => [Database\DVarP::class, 'evaluate'],
|
||||||
'argumentCount' => '3',
|
'argumentCount' => '3',
|
||||||
],
|
],
|
||||||
'EDATE' => [
|
'EDATE' => [
|
||||||
|
|
@ -3437,6 +3437,7 @@ class Calculation
|
||||||
$this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula);
|
$this->debugLog->writeDebugLog('Formula for cell ', $wsCellReference, ' is ', $formula);
|
||||||
// Parse the formula onto the token stack and calculate the value
|
// Parse the formula onto the token stack and calculate the value
|
||||||
$this->cyclicReferenceStack->push($wsCellReference);
|
$this->cyclicReferenceStack->push($wsCellReference);
|
||||||
|
|
||||||
$cellValue = $this->processTokenStack($this->internalParseFormula($formula, $pCell), $cellID, $pCell);
|
$cellValue = $this->processTokenStack($this->internalParseFormula($formula, $pCell), $cellID, $pCell);
|
||||||
$this->cyclicReferenceStack->pop();
|
$this->cyclicReferenceStack->pop();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,126 +2,11 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpSpreadsheet\Calculation;
|
namespace PhpOffice\PhpSpreadsheet\Calculation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 1.17.0
|
||||||
|
*/
|
||||||
class Database
|
class Database
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* fieldExtract.
|
|
||||||
*
|
|
||||||
* Extracts the column ID to use for the data field.
|
|
||||||
*
|
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
|
||||||
* A database is a list of related data in which rows of related
|
|
||||||
* information are records, and columns of data are fields. The
|
|
||||||
* first row of the list contains labels for each column.
|
|
||||||
* @param mixed $field Indicates which column is used in the function. Enter the
|
|
||||||
* column label enclosed between double quotation marks, such as
|
|
||||||
* "Age" or "Yield," or a number (without quotation marks) that
|
|
||||||
* represents the position of the column within the list: 1 for
|
|
||||||
* the first column, 2 for the second column, and so on.
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
private static function fieldExtract($database, $field)
|
|
||||||
{
|
|
||||||
$field = strtoupper(Functions::flattenSingleValue($field));
|
|
||||||
$fieldNames = array_map('strtoupper', array_shift($database));
|
|
||||||
|
|
||||||
if (is_numeric($field)) {
|
|
||||||
$keys = array_keys($fieldNames);
|
|
||||||
|
|
||||||
return $keys[$field - 1];
|
|
||||||
}
|
|
||||||
$key = array_search($field, $fieldNames);
|
|
||||||
|
|
||||||
return $key ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* filter.
|
|
||||||
*
|
|
||||||
* Parses the selection criteria, extracts the database rows that match those criteria, and
|
|
||||||
* returns that subset of rows.
|
|
||||||
*
|
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
|
||||||
* A database is a list of related data in which rows of related
|
|
||||||
* information are records, and columns of data are fields. The
|
|
||||||
* first row of the list contains labels for each column.
|
|
||||||
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
|
||||||
* You can use any range for the criteria argument, as long as it
|
|
||||||
* includes at least one column label and at least one cell below
|
|
||||||
* the column label in which you specify a condition for the
|
|
||||||
* column.
|
|
||||||
*
|
|
||||||
* @return array of mixed
|
|
||||||
*/
|
|
||||||
private static function filter($database, $criteria)
|
|
||||||
{
|
|
||||||
$fieldNames = array_shift($database);
|
|
||||||
$criteriaNames = array_shift($criteria);
|
|
||||||
|
|
||||||
// Convert the criteria into a set of AND/OR conditions with [:placeholders]
|
|
||||||
$testConditions = $testValues = [];
|
|
||||||
$testConditionsCount = 0;
|
|
||||||
foreach ($criteriaNames as $key => $criteriaName) {
|
|
||||||
$testCondition = [];
|
|
||||||
$testConditionCount = 0;
|
|
||||||
foreach ($criteria as $row => $criterion) {
|
|
||||||
if ($criterion[$key] > '') {
|
|
||||||
$testCondition[] = '[:' . $criteriaName . ']' . Functions::ifCondition($criterion[$key]);
|
|
||||||
++$testConditionCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($testConditionCount > 1) {
|
|
||||||
$testConditions[] = 'OR(' . implode(',', $testCondition) . ')';
|
|
||||||
++$testConditionsCount;
|
|
||||||
} elseif ($testConditionCount == 1) {
|
|
||||||
$testConditions[] = $testCondition[0];
|
|
||||||
++$testConditionsCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($testConditionsCount > 1) {
|
|
||||||
$testConditionSet = 'AND(' . implode(',', $testConditions) . ')';
|
|
||||||
} elseif ($testConditionsCount == 1) {
|
|
||||||
$testConditionSet = $testConditions[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through each row of the database
|
|
||||||
foreach ($database as $dataRow => $dataValues) {
|
|
||||||
// Substitute actual values from the database row for our [:placeholders]
|
|
||||||
$testConditionList = $testConditionSet;
|
|
||||||
foreach ($criteriaNames as $key => $criteriaName) {
|
|
||||||
$k = array_search($criteriaName, $fieldNames);
|
|
||||||
if (isset($dataValues[$k])) {
|
|
||||||
$dataValue = $dataValues[$k];
|
|
||||||
$dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue;
|
|
||||||
$testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// evaluate the criteria against the row data
|
|
||||||
$result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList);
|
|
||||||
// If the row failed to meet the criteria, remove it from the database
|
|
||||||
if (!$result) {
|
|
||||||
unset($database[$dataRow]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $database;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function getFilteredColumn($database, $field, $criteria)
|
|
||||||
{
|
|
||||||
// reduce the database to a set of rows that match all the criteria
|
|
||||||
$database = self::filter($database, $criteria);
|
|
||||||
// extract an array of values for the requested column
|
|
||||||
$colData = [];
|
|
||||||
foreach ($database as $row) {
|
|
||||||
$colData[] = $row[$field];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $colData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DAVERAGE.
|
* DAVERAGE.
|
||||||
*
|
*
|
||||||
|
|
@ -130,6 +15,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DAVERAGE(database,field,criteria)
|
* DAVERAGE(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DAverage class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -149,15 +38,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DAVERAGE($database, $field, $criteria)
|
public static function DAVERAGE($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DAverage::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::AVERAGE(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,14 +50,15 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DCOUNT(database,[field],criteria)
|
* DCOUNT(database,[field],criteria)
|
||||||
*
|
*
|
||||||
* Excel Function:
|
* @Deprecated 1.17.0
|
||||||
* DAVERAGE(database,field,criteria)
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DCount class instead
|
||||||
*
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
* first row of the list contains labels for each column.
|
* first row of the list contains labels for each column.
|
||||||
* @param int|string $field Indicates which column is used in the function. Enter the
|
* @param null|int|string $field Indicates which column is used in the function. Enter the
|
||||||
* column label enclosed between double quotation marks, such as
|
* column label enclosed between double quotation marks, such as
|
||||||
* "Age" or "Yield," or a number (without quotation marks) that
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
* represents the position of the column within the list: 1 for
|
* represents the position of the column within the list: 1 for
|
||||||
|
|
@ -194,15 +76,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DCOUNT($database, $field, $criteria)
|
public static function DCOUNT($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DCount::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::COUNT(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -213,11 +87,15 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DCOUNTA(database,[field],criteria)
|
* DCOUNTA(database,[field],criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DCountA class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
* first row of the list contains labels for each column.
|
* first row of the list contains labels for each column.
|
||||||
* @param int|string $field Indicates which column is used in the function. Enter the
|
* @param null|int|string $field Indicates which column is used in the function. Enter the
|
||||||
* column label enclosed between double quotation marks, such as
|
* column label enclosed between double quotation marks, such as
|
||||||
* "Age" or "Yield," or a number (without quotation marks) that
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
* represents the position of the column within the list: 1 for
|
* represents the position of the column within the list: 1 for
|
||||||
|
|
@ -229,29 +107,10 @@ class Database
|
||||||
* column.
|
* column.
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*
|
|
||||||
* @TODO The field argument is optional. If field is omitted, DCOUNTA counts all records in the
|
|
||||||
* database that match the criteria.
|
|
||||||
*/
|
*/
|
||||||
public static function DCOUNTA($database, $field, $criteria)
|
public static function DCOUNTA($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DCountA::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reduce the database to a set of rows that match all the criteria
|
|
||||||
$database = self::filter($database, $criteria);
|
|
||||||
// extract an array of values for the requested column
|
|
||||||
$colData = [];
|
|
||||||
foreach ($database as $row) {
|
|
||||||
$colData[] = $row[$field];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::COUNTA(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -263,6 +122,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DGET(database,field,criteria)
|
* DGET(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DGet class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -282,18 +145,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DGET($database, $field, $criteria)
|
public static function DGET($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DGet::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
$colData = self::getFilteredColumn($database, $field, $criteria);
|
|
||||||
if (count($colData) > 1) {
|
|
||||||
return Functions::NAN();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $colData[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -305,6 +157,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DMAX(database,field,criteria)
|
* DMAX(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DMax class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -324,15 +180,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DMAX($database, $field, $criteria)
|
public static function DMAX($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DMax::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::MAX(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -344,6 +192,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DMIN(database,field,criteria)
|
* DMIN(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DMin class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -363,15 +215,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DMIN($database, $field, $criteria)
|
public static function DMIN($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DMin::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::MIN(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -382,6 +226,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DPRODUCT(database,field,criteria)
|
* DPRODUCT(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DProduct class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -401,15 +249,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DPRODUCT($database, $field, $criteria)
|
public static function DPRODUCT($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DProduct::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return MathTrig::PRODUCT(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -421,6 +261,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DSTDEV(database,field,criteria)
|
* DSTDEV(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DStDev class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -440,15 +284,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DSTDEV($database, $field, $criteria)
|
public static function DSTDEV($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DStDev::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::STDEV(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -460,6 +296,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DSTDEVP(database,field,criteria)
|
* DSTDEVP(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DStDevP class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -479,15 +319,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DSTDEVP($database, $field, $criteria)
|
public static function DSTDEVP($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DStDevP::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::STDEVP(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -498,6 +330,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DSUM(database,field,criteria)
|
* DSUM(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DSum class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -517,15 +353,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DSUM($database, $field, $criteria)
|
public static function DSUM($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DSum::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return MathTrig::SUM(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -537,6 +365,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DVAR(database,field,criteria)
|
* DVAR(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DVar class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -556,15 +388,7 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DVAR($database, $field, $criteria)
|
public static function DVAR($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DVar::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::VARFunc(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -576,6 +400,10 @@ class Database
|
||||||
* Excel Function:
|
* Excel Function:
|
||||||
* DVARP(database,field,criteria)
|
* DVARP(database,field,criteria)
|
||||||
*
|
*
|
||||||
|
* @Deprecated 1.17.0
|
||||||
|
*
|
||||||
|
* @see Use the evaluate() method in the Database\DVarP class instead
|
||||||
|
*
|
||||||
* @param mixed[] $database The range of cells that makes up the list or database.
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
* A database is a list of related data in which rows of related
|
* A database is a list of related data in which rows of related
|
||||||
* information are records, and columns of data are fields. The
|
* information are records, and columns of data are fields. The
|
||||||
|
|
@ -595,14 +423,6 @@ class Database
|
||||||
*/
|
*/
|
||||||
public static function DVARP($database, $field, $criteria)
|
public static function DVARP($database, $field, $criteria)
|
||||||
{
|
{
|
||||||
$field = self::fieldExtract($database, $field);
|
return Database\DVarP::evaluate($database, $field, $criteria);
|
||||||
if ($field === null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return
|
|
||||||
return Statistical::VARP(
|
|
||||||
self::getFilteredColumn($database, $field, $criteria)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DAverage extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DAVERAGE.
|
||||||
|
*
|
||||||
|
* Averages the values in a column of a list or database that match conditions you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DAVERAGE(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::AVERAGE(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DCount extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DCOUNT.
|
||||||
|
*
|
||||||
|
* Counts the cells that contain numbers in a column of a list or database that match conditions
|
||||||
|
* that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DCOUNT(database,[field],criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param null|int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
|
||||||
|
return Statistical::COUNT(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DCountA extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DCOUNTA.
|
||||||
|
*
|
||||||
|
* Counts the nonblank cells in a column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DCOUNTA(database,[field],criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
|
||||||
|
return Statistical::COUNTA(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
class DGet extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DGET.
|
||||||
|
*
|
||||||
|
* Extracts a single value from a column of a list or database that matches conditions that you
|
||||||
|
* specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DGET(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$columnData = self::getFilteredColumn($database, $field, $criteria);
|
||||||
|
if (count($columnData) > 1) {
|
||||||
|
return Functions::NAN();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columnData[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DMax extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DMAX.
|
||||||
|
*
|
||||||
|
* Returns the largest number in a column of a list or database that matches conditions you that
|
||||||
|
* specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DMAX(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::MAX(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DMin extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DMIN.
|
||||||
|
*
|
||||||
|
* Returns the smallest number in a column of a list or database that matches conditions you that
|
||||||
|
* specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DMIN(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::MIN(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
|
||||||
|
|
||||||
|
class DProduct extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DPRODUCT.
|
||||||
|
*
|
||||||
|
* Multiplies the values in a column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DPRODUCT(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MathTrig::PRODUCT(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DStDev extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DSTDEV.
|
||||||
|
*
|
||||||
|
* Estimates the standard deviation of a population based on a sample by using the numbers in a
|
||||||
|
* column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DSTDEV(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::STDEV(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DStDevP extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DSTDEVP.
|
||||||
|
*
|
||||||
|
* Calculates the standard deviation of a population based on the entire population by using the
|
||||||
|
* numbers in a column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DSTDEVP(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float|string
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::STDEVP(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
|
||||||
|
|
||||||
|
class DSum extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DSUM.
|
||||||
|
*
|
||||||
|
* Adds the numbers in a column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DSUM(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MathTrig::SUM(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DVar extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DVAR.
|
||||||
|
*
|
||||||
|
* Estimates the variance of a population based on a sample by using the numbers in a column
|
||||||
|
* of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DVAR(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float|string (string if result is an error)
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::VARFunc(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
|
||||||
|
|
||||||
|
class DVarP extends DatabaseAbstract
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* DVARP.
|
||||||
|
*
|
||||||
|
* Calculates the variance of a population based on the entire population by using the numbers
|
||||||
|
* in a column of a list or database that match conditions that you specify.
|
||||||
|
*
|
||||||
|
* Excel Function:
|
||||||
|
* DVARP(database,field,criteria)
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param int|string $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return float|string (string if result is an error)
|
||||||
|
*/
|
||||||
|
public static function evaluate($database, $field, $criteria)
|
||||||
|
{
|
||||||
|
$field = self::fieldExtract($database, $field);
|
||||||
|
if ($field === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Statistical::VARP(
|
||||||
|
self::getFilteredColumn($database, $field, $criteria)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
|
||||||
|
abstract class DatabaseAbstract
|
||||||
|
{
|
||||||
|
abstract public static function evaluate($database, $field, $criteria);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fieldExtract.
|
||||||
|
*
|
||||||
|
* Extracts the column ID to use for the data field.
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param mixed $field Indicates which column is used in the function. Enter the
|
||||||
|
* column label enclosed between double quotation marks, such as
|
||||||
|
* "Age" or "Yield," or a number (without quotation marks) that
|
||||||
|
* represents the position of the column within the list: 1 for
|
||||||
|
* the first column, 2 for the second column, and so on.
|
||||||
|
*/
|
||||||
|
protected static function fieldExtract(array $database, $field): ?string
|
||||||
|
{
|
||||||
|
$field = strtoupper(Functions::flattenSingleValue($field));
|
||||||
|
$fieldNames = array_map('strtoupper', array_shift($database));
|
||||||
|
|
||||||
|
if (is_numeric($field)) {
|
||||||
|
$keys = array_keys($fieldNames);
|
||||||
|
|
||||||
|
return $keys[$field - 1];
|
||||||
|
}
|
||||||
|
$key = array_search($field, $fieldNames);
|
||||||
|
|
||||||
|
return $key ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* filter.
|
||||||
|
*
|
||||||
|
* Parses the selection criteria, extracts the database rows that match those criteria, and
|
||||||
|
* returns that subset of rows.
|
||||||
|
*
|
||||||
|
* @param mixed[] $database The range of cells that makes up the list or database.
|
||||||
|
* A database is a list of related data in which rows of related
|
||||||
|
* information are records, and columns of data are fields. The
|
||||||
|
* first row of the list contains labels for each column.
|
||||||
|
* @param mixed[] $criteria The range of cells that contains the conditions you specify.
|
||||||
|
* You can use any range for the criteria argument, as long as it
|
||||||
|
* includes at least one column label and at least one cell below
|
||||||
|
* the column label in which you specify a condition for the
|
||||||
|
* column.
|
||||||
|
*
|
||||||
|
* @return array of mixed
|
||||||
|
*/
|
||||||
|
protected static function filter(array $database, array $criteria): array
|
||||||
|
{
|
||||||
|
$fieldNames = array_shift($database);
|
||||||
|
$criteriaNames = array_shift($criteria);
|
||||||
|
|
||||||
|
// Convert the criteria into a set of AND/OR conditions with [:placeholders]
|
||||||
|
$query = self::buildQuery($criteriaNames, $criteria);
|
||||||
|
|
||||||
|
// Loop through each row of the database
|
||||||
|
return self::executeQuery($database, $query, $criteriaNames, $fieldNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getFilteredColumn(array $database, $field, array $criteria): array
|
||||||
|
{
|
||||||
|
// reduce the database to a set of rows that match all the criteria
|
||||||
|
$database = self::filter($database, $criteria);
|
||||||
|
// extract an array of values for the requested column
|
||||||
|
$columnData = [];
|
||||||
|
foreach ($database as $row) {
|
||||||
|
$columnData[] = ($field !== null) ? $row[$field] : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $columnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @TODO Support for Dates (including handling for >, <=, etc)
|
||||||
|
* @TODO Suport for formatted numerics (e.g. '>12.5%' => '>0.125')
|
||||||
|
* @TODO Suport for wildcard ? and * in strings (includng escaping)
|
||||||
|
*/
|
||||||
|
private static function buildQuery(array $criteriaNames, array $criteria): string
|
||||||
|
{
|
||||||
|
$baseQuery = [];
|
||||||
|
foreach ($criteria as $key => $criterion) {
|
||||||
|
foreach ($criterion as $field => $value) {
|
||||||
|
$criterionName = $criteriaNames[$field];
|
||||||
|
if ($value !== null && $value !== '') {
|
||||||
|
$condition = '[:' . $criterionName . ']' . Functions::ifCondition($value);
|
||||||
|
$baseQuery[$key][] = $condition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rowQuery = array_map(
|
||||||
|
function ($rowValue) {
|
||||||
|
return (count($rowValue) > 1) ? 'AND(' . implode(',', $rowValue) . ')' : $rowValue[0];
|
||||||
|
},
|
||||||
|
$baseQuery
|
||||||
|
);
|
||||||
|
|
||||||
|
return (count($rowQuery) > 1) ? 'OR(' . implode(',', $rowQuery) . ')' : $rowQuery[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $criteriaNames
|
||||||
|
* @param $fieldNames
|
||||||
|
*/
|
||||||
|
private static function executeQuery(array $database, string $query, $criteriaNames, $fieldNames): array
|
||||||
|
{
|
||||||
|
foreach ($database as $dataRow => $dataValues) {
|
||||||
|
// Substitute actual values from the database row for our [:placeholders]
|
||||||
|
$testConditionList = $query;
|
||||||
|
foreach ($criteriaNames as $key => $criteriaName) {
|
||||||
|
$key = array_search($criteriaName, $fieldNames, true);
|
||||||
|
if (isset($dataValues[$key])) {
|
||||||
|
$dataValue = $dataValues[$key];
|
||||||
|
$dataValue = (is_string($dataValue)) ? Calculation::wrapResult(strtoupper($dataValue)) : $dataValue;
|
||||||
|
} else {
|
||||||
|
$dataValue = 'NULL';
|
||||||
|
}
|
||||||
|
$testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// evaluate the criteria against the row data
|
||||||
|
$result = Calculation::getInstance()->_calculateFormulaValue('=' . $testConditionList);
|
||||||
|
// If the row failed to meet the criteria, remove it from the database
|
||||||
|
|
||||||
|
if ($result !== true) {
|
||||||
|
unset($database[$dataRow]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $database;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DAverageTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDAverage
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDAverage($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DAVERAGE($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 76.8],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Quarter', 'Area', 'Sales Rep.', 'Sales'],
|
||||||
|
[1, 'North', 'Jeff', 223000],
|
||||||
|
[1, 'North', 'Chris', 125000],
|
||||||
|
[1, 'South', 'Carol', 456000],
|
||||||
|
[1, 'South', 'Tina', 289000],
|
||||||
|
[2, 'North', 'Jeff', 322000],
|
||||||
|
[2, 'North', 'Chris', 340000],
|
||||||
|
[2, 'South', 'Carol', 198000],
|
||||||
|
[2, 'South', 'Tina', 222000],
|
||||||
|
[3, 'North', 'Jeff', 310000],
|
||||||
|
[3, 'North', 'Chris', 250000],
|
||||||
|
[3, 'South', 'Carol', 460000],
|
||||||
|
[3, 'South', 'Tina', 395000],
|
||||||
|
[4, 'North', 'Jeff', 261000],
|
||||||
|
[4, 'North', 'Chris', 389000],
|
||||||
|
[4, 'South', 'Carol', 305000],
|
||||||
|
[4, 'South', 'Tina', 188000],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDAverage()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
12,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree', 'Height'],
|
||||||
|
['=Apple', '>10'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
13,
|
||||||
|
$this->database1(),
|
||||||
|
3,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
268333.333333333333,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Quarter', 'Sales Rep.'],
|
||||||
|
['>1', 'Tina'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
372500,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Quarter', 'Area'],
|
||||||
|
['1', 'South'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DCountATest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDCountA
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDCountA($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DCOUNTA($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 76.8],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 8, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 8, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 8, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 'awaiting'],
|
||||||
|
['Sue', 'Female', 9, 'Math', null],
|
||||||
|
['Sue', 'Female', 9, 'English', 0.52],
|
||||||
|
['Sue', 'Female', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDCountA()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
$this->database1(),
|
||||||
|
'Profit',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
2,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Science', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
* Null value in datacolumn behaviour for DCOUNTA... will include not include a null value in the count
|
||||||
|
* if it is an actual cell value; but it will be included if it is a literal... this test case is
|
||||||
|
* currently passing literals
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Math', 'Female'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
[
|
||||||
|
3,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Score'],
|
||||||
|
['English', '>0.60'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DCountTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDCount
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDCount($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DCOUNT($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 'N/A', 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 12, 11, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 8, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 8, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 8, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 'awaiting'],
|
||||||
|
['Sue', 'Female', 9, 'Math', null],
|
||||||
|
['Sue', 'Female', 9, 'English', 0.52],
|
||||||
|
['Sue', 'Female', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDCount()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
$this->database1(),
|
||||||
|
'Age',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Science', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Math', 'Female'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
3,
|
||||||
|
$this->database2(),
|
||||||
|
null,
|
||||||
|
[
|
||||||
|
['Subject', 'Score'],
|
||||||
|
['English', '>0.63'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DGetTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDGet
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDGet($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DGET($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Quarter', 'Area', 'Sales Rep.', 'Sales'],
|
||||||
|
[1, 'North', 'Jeff', 223000],
|
||||||
|
[1, 'North', 'Chris', 125000],
|
||||||
|
[1, 'South', 'Carol', 456000],
|
||||||
|
[1, 'South', 'Tina', 289000],
|
||||||
|
[2, 'North', 'Jeff', 322000],
|
||||||
|
[2, 'North', 'Chris', 340000],
|
||||||
|
[2, 'South', 'Carol', 198000],
|
||||||
|
[2, 'South', 'Tina', 222000],
|
||||||
|
[3, 'North', 'Jeff', 310000],
|
||||||
|
[3, 'North', 'Chris', 250000],
|
||||||
|
[3, 'South', 'Carol', 460000],
|
||||||
|
[3, 'South', 'Tina', 395000],
|
||||||
|
[4, 'North', 'Jeff', 261000],
|
||||||
|
[4, 'North', 'Chris', 389000],
|
||||||
|
[4, 'South', 'Carol', 305000],
|
||||||
|
[4, 'South', 'Tina', 188000],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDGet()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
Functions::NAN(),
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
['=Pear'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
10,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
['=Pear', '>12', null],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
188000,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Sales Rep.', 'Quarter'],
|
||||||
|
['Tina', 4],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Functions::NAN(),
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Area', 'Quarter'],
|
||||||
|
['South', 4],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DMaxTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDMax
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDMax($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DMAX($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Quarter', 'Area', 'Sales Rep.', 'Sales'],
|
||||||
|
[1, 'North', 'Jeff', 223000],
|
||||||
|
[1, 'North', 'Chris', 125000],
|
||||||
|
[1, 'South', 'Carol', 456000],
|
||||||
|
[1, 'South', 'Tina', 289000],
|
||||||
|
[2, 'North', 'Jeff', 322000],
|
||||||
|
[2, 'North', 'Chris', 340000],
|
||||||
|
[2, 'South', 'Carol', 198000],
|
||||||
|
[2, 'South', 'Tina', 222000],
|
||||||
|
[3, 'North', 'Jeff', 310000],
|
||||||
|
[3, 'North', 'Chris', 250000],
|
||||||
|
[3, 'South', 'Carol', 460000],
|
||||||
|
[3, 'South', 'Tina', 395000],
|
||||||
|
[4, 'North', 'Jeff', 261000],
|
||||||
|
[4, 'North', 'Chris', 389000],
|
||||||
|
[4, 'South', 'Carol', 305000],
|
||||||
|
[4, 'South', 'Tina', 188000],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDMax()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
96,
|
||||||
|
$this->database1(),
|
||||||
|
'Profit',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
['=Pear', null, null],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
340000,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Quarter', 'Area'],
|
||||||
|
[2, 'North'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
460000,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Sales Rep.', 'Quarter'],
|
||||||
|
['Carol', '>1'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DMinTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDMin
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDMin($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DMIN($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 8, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 8, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 8, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 0.51],
|
||||||
|
['Sue', 'Female', 9, 'Math', 0.39],
|
||||||
|
['Sue', 'Female', 9, 'English', 0.52],
|
||||||
|
['Sue', 'Female', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDMin()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
75,
|
||||||
|
$this->database1(),
|
||||||
|
'Profit',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
['=Pear', '>12', null],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.48,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Age'],
|
||||||
|
['Science', '>8'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.55,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Math', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DProductTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDProduct
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDProduct($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DPRODUCT($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Date', 'Test', 'Score'],
|
||||||
|
['Gary', DateTime::getDateValue('01-Jan-2017'), 'Test1', 4],
|
||||||
|
['Gary', DateTime::getDateValue('01-Jan-2017'), 'Test2', 4],
|
||||||
|
['Gary', DateTime::getDateValue('01-Jan-2017'), 'Test3', 3],
|
||||||
|
['Gary', DateTime::getDateValue('05-Jan-2017'), 'Test1', 3],
|
||||||
|
['Gary', DateTime::getDateValue('05-Jan-2017'), 'Test2', 4],
|
||||||
|
['Gary', DateTime::getDateValue('05-Jan-2017'), 'Test3', 3],
|
||||||
|
['Kev', DateTime::getDateValue('02-Jan-2017'), 'Test1', 2],
|
||||||
|
['Kev', DateTime::getDateValue('02-Jan-2017'), 'Test2', 3],
|
||||||
|
['Kev', DateTime::getDateValue('02-Jan-2017'), 'Test3', 5],
|
||||||
|
['Kev', DateTime::getDateValue('05-Jan-2017'), 'Test1', 3],
|
||||||
|
['Kev', DateTime::getDateValue('05-Jan-2017'), 'Test2', 2],
|
||||||
|
['Kev', DateTime::getDateValue('05-Jan-2017'), 'Test3', 5],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDProduct()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
800,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
['=Pear', null, null],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
* We don't yet support date handling in the search query
|
||||||
|
[
|
||||||
|
36,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Name', 'Date'],
|
||||||
|
['Gary', '05-Jan-2017'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
8,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Test', 'Date'],
|
||||||
|
['Test1', '<05-Jan-2017'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DStDevPTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDStDevP
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDStDevP($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DSTDEVP($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 10, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 10, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 10, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 0.51],
|
||||||
|
['Sam', 'Male', 9, 'Math', 0.39],
|
||||||
|
['Sam', 'Male', 9, 'English', 0.52],
|
||||||
|
['Sam', 'Male', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDStDevP()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
2.653299832284,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
['=Pear'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.085244745684,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['English', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.160623784042,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Age'],
|
||||||
|
['Math', '>8'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DStDevTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDStDev
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDStDev($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DSTDEV($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 10, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 10, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 10, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 0.51],
|
||||||
|
['Sam', 'Male', 9, 'Math', 0.39],
|
||||||
|
['Sam', 'Male', 9, 'English', 0.52],
|
||||||
|
['Sam', 'Male', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDStDev()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
2.966479394838,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
['=Pear'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.104403065089,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['English', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.196723155729,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Age'],
|
||||||
|
['Math', '>8'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DSumTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDSum
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDSum($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DSUM($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Quarter', 'Area', 'Sales Rep.', 'Sales'],
|
||||||
|
[1, 'North', 'Jeff', 223000],
|
||||||
|
[1, 'North', 'Chris', 125000],
|
||||||
|
[1, 'South', 'Carol', 456000],
|
||||||
|
[1, 'South', 'Tina', 289000],
|
||||||
|
[2, 'North', 'Jeff', 322000],
|
||||||
|
[2, 'North', 'Chris', 340000],
|
||||||
|
[2, 'South', 'Carol', 198000],
|
||||||
|
[2, 'South', 'Tina', 222000],
|
||||||
|
[3, 'North', 'Jeff', 310000],
|
||||||
|
[3, 'North', 'Chris', 250000],
|
||||||
|
[3, 'South', 'Carol', 460000],
|
||||||
|
[3, 'South', 'Tina', 395000],
|
||||||
|
[4, 'North', 'Jeff', 261000],
|
||||||
|
[4, 'North', 'Chris', 389000],
|
||||||
|
[4, 'South', 'Carol', 305000],
|
||||||
|
[4, 'South', 'Tina', 188000],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDSum()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
225,
|
||||||
|
$this->database1(),
|
||||||
|
'Profit',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
248,
|
||||||
|
$this->database1(),
|
||||||
|
'Profit',
|
||||||
|
[
|
||||||
|
['Tree', 'Height', 'Height'],
|
||||||
|
['=Apple', '>10', '<16'],
|
||||||
|
['=Pear', null, null],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1210000,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Quarter', 'Area'],
|
||||||
|
['>2', 'North'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
* We don't yet support woldcards in text search fields
|
||||||
|
[
|
||||||
|
710000,
|
||||||
|
$this->database2(),
|
||||||
|
'Sales',
|
||||||
|
[
|
||||||
|
['Quarter', 'Sales Rep.'],
|
||||||
|
['3', 'C*'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DVarPTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDVarP
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDVarP($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DVARP($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 10, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 10, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 10, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 0.51],
|
||||||
|
['Sam', 'Male', 9, 'Math', 0.39],
|
||||||
|
['Sam', 'Male', 9, 'English', 0.52],
|
||||||
|
['Sam', 'Male', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDVarP()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
7.04,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
['=Pear'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.025622222222,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Math', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.011622222222,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Age'],
|
||||||
|
['Science', '>8'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Database;
|
||||||
|
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Database;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class DVarTest extends TestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider providerDVar
|
||||||
|
*
|
||||||
|
* @param mixed $expectedResult
|
||||||
|
* @param mixed $database
|
||||||
|
* @param mixed $field
|
||||||
|
* @param mixed $criteria
|
||||||
|
*/
|
||||||
|
public function testDVar($expectedResult, $database, $field, $criteria): void
|
||||||
|
{
|
||||||
|
$result = Database::DVAR($database, $field, $criteria);
|
||||||
|
self::assertSame($expectedResult, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database1()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Tree', 'Height', 'Age', 'Yield', 'Profit'],
|
||||||
|
['Apple', 18, 20, 14, 105],
|
||||||
|
['Pear', 12, 12, 10, 96],
|
||||||
|
['Cherry', 13, 14, 9, 105],
|
||||||
|
['Apple', 14, 15, 10, 75],
|
||||||
|
['Pear', 9, 8, 8, 77],
|
||||||
|
['Apple', 8, 9, 6, 45],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function database2()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
['Name', 'Gender', 'Age', 'Subject', 'Score'],
|
||||||
|
['Amy', 'Female', 10, 'Math', 0.63],
|
||||||
|
['Amy', 'Female', 10, 'English', 0.78],
|
||||||
|
['Amy', 'Female', 10, 'Science', 0.39],
|
||||||
|
['Bill', 'Male', 8, 'Math', 0.55],
|
||||||
|
['Bill', 'Male', 8, 'English', 0.71],
|
||||||
|
['Bill', 'Male', 8, 'Science', 0.51],
|
||||||
|
['Sam', 'Male', 9, 'Math', 0.39],
|
||||||
|
['Sam', 'Male', 9, 'English', 0.52],
|
||||||
|
['Sam', 'Male', 9, 'Science', 0.48],
|
||||||
|
['Tom', 'Male', 9, 'Math', 0.78],
|
||||||
|
['Tom', 'Male', 9, 'English', 0.69],
|
||||||
|
['Tom', 'Male', 9, 'Science', 0.65],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function providerDVar()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
8.8,
|
||||||
|
$this->database1(),
|
||||||
|
'Yield',
|
||||||
|
[
|
||||||
|
['Tree'],
|
||||||
|
['=Apple'],
|
||||||
|
['=Pear'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.038433333333,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Gender'],
|
||||||
|
['Math', 'Male'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0.017433333333,
|
||||||
|
$this->database2(),
|
||||||
|
'Score',
|
||||||
|
[
|
||||||
|
['Subject', 'Age'],
|
||||||
|
['Science', '>8'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
null,
|
||||||
|
$this->database1(),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue