diff --git a/src/Builder/ArrayMergeBuilder.php b/src/Builder/ArrayMergeBuilder.php index 29eb4644..a603c8a4 100644 --- a/src/Builder/ArrayMergeBuilder.php +++ b/src/Builder/ArrayMergeBuilder.php @@ -42,21 +42,17 @@ final class ArrayMergeBuilder extends MultiOperandFunctionBuilder protected function buildFromExpression(MultiOperandFunction $expression, array &$params): string { $operandType = $this->buildOperandType($expression->getType()); - $selects = []; + $builtOperands = []; foreach ($expression->getOperands() as $operand) { - $builtOperand = $this->buildOperand($operand, $params); - - $selects[] = "SELECT value FROM JSON_TABLE($builtOperand, '$[*]' COLUMNS(value $operandType PATH '$')) AS t"; + $builtOperands[] = $this->buildOperand($operand, $params); } - $unions = implode(' UNION ', $selects); - - if ($expression->getOrdered()) { - $unions .= ' ORDER BY value'; - } + $orderBy = $expression->getOrdered() ? ' ORDER BY value' : ''; - return '(SELECT JSON_ARRAYAGG(value) AS value FROM (' . $unions . ') AS t)'; + return "(SELECT JSON_ARRAYAGG(DISTINCT value$orderBy) AS value" + . ' FROM JSON_TABLE(JSON_MERGE_PRESERVE(' . implode(', ', $builtOperands) . '),' + . " '$[*]' COLUMNS(value $operandType PATH '$')) AS t)"; } private function buildOperandType(string|ColumnInterface $type): string diff --git a/tests/Provider/QueryBuilderProvider.php b/tests/Provider/QueryBuilderProvider.php index 096a50a3..eb35dc04 100644 --- a/tests/Provider/QueryBuilderProvider.php +++ b/tests/Provider/QueryBuilderProvider.php @@ -360,10 +360,8 @@ public static function multiOperandFunctionBuilder(): array $data['ArrayMerge with 2 operands'] = [ ArrayMerge::class, ["'[1,2,3]'", $stringParam], - '(SELECT JSON_ARRAYAGG(value) AS value FROM (' - . "SELECT value FROM JSON_TABLE('[1,2,3]', '$[*]' COLUMNS(value json PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE(:qp0, '$[*]' COLUMNS(value json PATH '$')) AS t" - . ') AS t)', + '(SELECT JSON_ARRAYAGG(DISTINCT value) AS value' + . " FROM JSON_TABLE(JSON_MERGE_PRESERVE('[1,2,3]', :qp0), '$[*]' COLUMNS(value json PATH '$')) AS t)", [1, 2, 3, 4, 5], [':qp0' => $stringParam], ]; @@ -373,12 +371,9 @@ public static function multiOperandFunctionBuilder(): array $data['ArrayMerge with 4 operands'] = [ ArrayMerge::class, ["'[1,2,3]'", [5, 6, 7], $stringParam, self::getDb()->select(new ArrayValue([9, 10]))], - '(SELECT JSON_ARRAYAGG(value) AS value FROM (' - . "SELECT value FROM JSON_TABLE('[1,2,3]', '$[*]' COLUMNS(value json PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE(:qp0, '$[*]' COLUMNS(value json PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE(:qp1, '$[*]' COLUMNS(value json PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE((SELECT :qp2), '$[*]' COLUMNS(value json PATH '$')) AS t" - . ') AS t)', + '(SELECT JSON_ARRAYAGG(DISTINCT value) AS value' + . " FROM JSON_TABLE(JSON_MERGE_PRESERVE('[1,2,3]', :qp0, :qp1, (SELECT :qp2))," + . " '$[*]' COLUMNS(value json PATH '$')) AS t)", [1, 2, 3, 4, 5, 6, 7, 9, 10], [ ':qp0' => new Param('[5,6,7]', DataType::STRING), diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 0ff74f26..e78bb2a0 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -835,11 +835,9 @@ public function testArrayMergeWithTypeWithOrdering( $params = []; $this->assertSame( - '(SELECT JSON_ARRAYAGG(value) AS value FROM (' - . "SELECT value FROM JSON_TABLE('[2,1,3]', '$[*]' COLUMNS(value $operandType PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE(:qp0, '$[*]' COLUMNS(value $operandType PATH '$')) AS t" - . " UNION SELECT value FROM JSON_TABLE(:qp1, '$[*]' COLUMNS(value $operandType PATH '$')) AS t" - . ' ORDER BY value) AS t)', + '(SELECT JSON_ARRAYAGG(DISTINCT value ORDER BY value) AS value' + . " FROM JSON_TABLE(JSON_MERGE_PRESERVE('[2,1,3]', :qp0, :qp1)," + . " '$[*]' COLUMNS(value $operandType PATH '$')) AS t)", $qb->buildExpression($arrayMerge, $params) ); Assert::arraysEquals(