diff --git a/src/main/asciidoc/query-languages/sql/chapter.adoc b/src/main/asciidoc/query-languages/sql/chapter.adoc index 283765d5..6f2f9147 100644 --- a/src/main/asciidoc/query-languages/sql/chapter.adoc +++ b/src/main/asciidoc/query-languages/sql/chapter.adoc @@ -34,17 +34,17 @@ image:../images/edit.png[link="https://github.com/ArcadeData/arcadedb-docs/blob/ | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | <> | | <> | <> -| <> | <> | <> | | <> | <> -| | | | | | <> -| <> | <> | <> | | <> | <> -| <> | <> | <> | | <> | <> -| <> | <> | | | <> | <> -| <> | <> | | | <> | <> -| <> | <> | | | <> | <> -| <> | <> | | | <> | <> -| <> | | | | <> | <> -| | | | | <> | <> -| | | | | <> | <> +| <> | <> | <> | | <> | <> +| | | | | | <> +| <> | <> | <> | | <> | <> +| <> | <> | <> | | <> | <> +| <> | <> | | | <> | <> +| <> | <> | | | <> | <> +| <> | <> | | | <> | <> +| <> | <> | | | <> | <> +| <> | | | | <> | <> +| | | | | <> | <> +| | | | | <> | | | | | | <> | | | | | | <> | | | | | | <> | diff --git a/src/main/asciidoc/query-languages/sql/sql-create-index.adoc b/src/main/asciidoc/query-languages/sql/sql-create-index.adoc index 1fe1ba1a..0539d56b 100644 --- a/src/main/asciidoc/query-languages/sql/sql-create-index.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-create-index.adoc @@ -27,7 +27,7 @@ CREATE INDEX [] [ IF NOT EXISTS ] [ ON ( [BY KEY|VALUE|ITEM][,]*) ] [] -[ NULL_STRATEGY SKIP|ERROR] +[ NULL_STRATEGY SKIP|ERROR|INDEX] ---- @@ -59,7 +59,11 @@ In order to create an index, the schema must already exist in your database. In the event that the `ON` and `<key-type>` clauses both exist, the database validates the specified property types. If the property types don't equal those specified in the key type list, it throws an exception. -NOTE: Null values are not indexed, so any query that is looking for null values will not use the index with a full scan. +The `NULL_STRATEGY` determines how null values are indexed: + +* `SKIP` (default) excludes null values from the index, +* `ERROR` throws an error in case a null value is found during indexing, +* `INDEX` adds null values to the index. NOTE: A unique index does not regard derived types or embedded documents of the indexed type. diff --git a/src/main/asciidoc/query-languages/sql/sql-create-type.adoc b/src/main/asciidoc/query-languages/sql/sql-create-type.adoc index b969fd4a..3337019a 100644 --- a/src/main/asciidoc/query-languages/sql/sql-create-type.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-create-type.adoc @@ -11,7 +11,7 @@ Creates a new type in the schema. ---- CREATE TYPE [UNIDIRECTIONAL] [ IF NOT EXISTS ] -[EXTENDS ] [BUCKET [,]*] [BUCKETS ] +[EXTENDS ] [BUCKET [,]*] [BUCKETS ] [PAGESIZE ] ---- @@ -24,6 +24,7 @@ CREATE TYPE * *`<super-type>`* Defines the super-type you want to extend with this type. * *`<bucket-id>`* Defines in a comma-separated list the ID's of the buckets you want this type to use. * *`<total-bucket-number>`* Defines the total number of buckets you want to create for this type. The default value is `1`. +* *`<page-size>`* Defines the page size of the type. In the event that a bucket of the same name exists in the bucket, the new type uses this bucket by default. If you do not define a bucket in the command and a bucket of this name does not exist, ArcadeDB creates one. The new bucket has the same name as the type, diff --git a/src/main/asciidoc/query-languages/sql/sql-functions.adoc b/src/main/asciidoc/query-languages/sql/sql-functions.adoc index 189cdab0..434eaa85 100644 --- a/src/main/asciidoc/query-languages/sql/sql-functions.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-functions.adoc @@ -564,182 +564,6 @@ SELECT if( (name = 'John'), "My name is John", "My name is not John") FROM Perso ''' -[discrete] -[[case-expression]] -===== CASE Expression - -NOTE: Available from version *26.2.1* - -The `CASE` expression provides conditional logic similar to if-then-else statements in programming languages. -It supports two forms: **searched CASE** and **simple CASE**. - -*Searched CASE Syntax* - -Evaluates conditions sequentially and returns the result of the first matching condition: - -[source,sql] ----- -CASE - WHEN THEN - WHEN THEN - [ELSE ] -END ----- - -*Simple CASE Syntax* - -Compares an expression against multiple values: - -[source,sql] ----- -CASE - WHEN THEN - WHEN THEN - [ELSE ] -END ----- - -*Behavior* - -* The `CASE` expression evaluates conditions in order and returns the result of the first matching `WHEN` clause -* If no conditions match and an `ELSE` clause is provided, the `ELSE` result is returned -* If no conditions match and there is no `ELSE` clause, `null` is returned -* Multiple `WHEN` clauses can be specified -* Can be used in `SELECT` projections, `WHERE` clauses, `MATCH` statements, `LET` clauses, and expressions -* Supports nested `CASE` expressions for complex conditional logic -* `NULL` values in conditions follow SQL three-valued logic (NULL comparisons return NULL, which is treated as false) - -*Examples* - -Searched CASE with conditions in SELECT: - -[source,sql] ----- -SELECT - name, - CASE - WHEN age < 18 THEN 'Minor' - WHEN age >= 18 AND age < 65 THEN 'Adult' - ELSE 'Senior' - END as ageGroup -FROM Person ----- - -Simple CASE with value matching: - -[source,sql] ----- -SELECT - name, - CASE status - WHEN 'active' THEN 1 - WHEN 'inactive' THEN 0 - ELSE -1 - END as statusCode -FROM Account ----- - -CASE without ELSE (returns null if no match): - -[source,sql] ----- -SELECT - name, - CASE - WHEN score > 90 THEN 'Excellent' - WHEN score > 75 THEN 'Good' - END as grade -FROM Student ----- - -CASE in WHERE clause for filtering: - -[source,sql] ----- -SELECT name, age -FROM Person -WHERE CASE - WHEN age IS NULL THEN false - WHEN age < 18 THEN 'minor' - ELSE 'adult' -END = 'adult' ----- - -CASE in MATCH WHERE clause (enum-to-string conversion with pattern matching): - -[source,sql] ----- -MATCH {type: Product, as: prod, - where: ((CASE - WHEN color = 1 THEN 'red' - WHEN color = 2 THEN 'blue' - WHEN color = 3 THEN 'green' - END) ILIKE '%ed%')} -RETURN prod.name ----- - -This is particularly useful for converting enum values (stored as integers) to human-readable strings that can be filtered with wildcards. - -CASE in MATCH RETURN clause: - -[source,sql] ----- -MATCH {type: Person, as: p, where: (age IS NOT NULL)} -RETURN p.name, - CASE - WHEN p.age < 18 THEN 'minor' - WHEN p.age < 65 THEN 'adult' - ELSE 'senior' - END as category -ORDER BY p.name ----- - -Nested CASE expressions: - -[source,sql] ----- -SELECT - name, - CASE - WHEN balance > 0 THEN - CASE - WHEN balance > 10000 THEN 'Premium' - ELSE 'Standard' - END - ELSE 'Overdrawn' - END as accountStatus -FROM Account ----- - -CASE in LET clause: - -[source,sql] ----- -SELECT $category -FROM Product -LET $category = CASE - WHEN price < 10 THEN 'Budget' - WHEN price < 100 THEN 'Standard' - ELSE 'Premium' -END ----- - -CASE with NULL handling: - -[source,sql] ----- -SELECT - name, - CASE - WHEN age IS NULL THEN 'Unknown' - WHEN age < 18 THEN 'Minor' - ELSE 'Adult' - END as status -FROM Person ----- - -''' - [discrete] [[ifempty-function]] ===== ifempty() [Function] diff --git a/src/main/asciidoc/query-languages/sql/sql-introduction.adoc b/src/main/asciidoc/query-languages/sql/sql-introduction.adoc index d7c25546..ab1fa349 100644 --- a/src/main/asciidoc/query-languages/sql/sql-introduction.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-introduction.adoc @@ -276,16 +276,6 @@ Following are some basic differences between ArcadeDB and PostgreSQL. | `SELECT * FROM pg_database` | `SELECT FROM schema:database` |=== - - - - - - - - - - However, there is a SQL condition where the two systems do differ. When you use functions that do not affect the column name, SQL defines that function name as the column name. In ArcadeDB, since we're projecting from a record, the resulting name remains the property name. diff --git a/src/main/asciidoc/query-languages/sql/sql-projections.adoc b/src/main/asciidoc/query-languages/sql/sql-projections.adoc index 0352a80d..8d162c05 100644 --- a/src/main/asciidoc/query-languages/sql/sql-projections.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-projections.adoc @@ -376,3 +376,177 @@ SELECT name, parent.parent:{name AS givenname} as grandparent FROM TheType WHERE } } ---- + +[discrete] +[[case-expression]] +===== CASE Expression + +NOTE: Available from version *26.2.1* + +The `CASE` expression provides conditional logic similar to if-then-else statements in programming languages. +It supports two forms: **searched CASE** and **simple CASE**. + +*Searched CASE Syntax* + +Evaluates conditions sequentially and returns the result of the first matching condition: + +[source,sql] +---- +CASE + WHEN THEN + WHEN THEN + [ELSE ] +END +---- + +*Simple CASE Syntax* + +Compares an expression against multiple values: + +[source,sql] +---- +CASE + WHEN THEN + WHEN THEN + [ELSE ] +END +---- + +*Behavior* + +* The `CASE` expression evaluates conditions in order and returns the result of the first matching `WHEN` clause +* If no conditions match and an `ELSE` clause is provided, the `ELSE` result is returned +* If no conditions match and there is no `ELSE` clause, `null` is returned +* Multiple `WHEN` clauses can be specified +* Can be used in `SELECT` projections, `WHERE` clauses, `MATCH` statements, `LET` clauses, and expressions +* Supports nested `CASE` expressions for complex conditional logic +* `NULL` values in conditions follow SQL three-valued logic (NULL comparisons return NULL, which is treated as false) + +*Examples* + +Searched CASE with conditions in SELECT: + +[source,sql] +---- +SELECT + name, + CASE + WHEN age < 18 THEN 'Minor' + WHEN age >= 18 AND age < 65 THEN 'Adult' + ELSE 'Senior' + END as ageGroup +FROM Person +---- + +Simple CASE with value matching: + +[source,sql] +---- +SELECT + name, + CASE status + WHEN 'active' THEN 1 + WHEN 'inactive' THEN 0 + ELSE -1 + END as statusCode +FROM Account +---- + +CASE without ELSE (returns null if no match): + +[source,sql] +---- +SELECT + name, + CASE + WHEN score > 90 THEN 'Excellent' + WHEN score > 75 THEN 'Good' + END as grade +FROM Student +---- + +CASE in WHERE clause for filtering: + +[source,sql] +---- +SELECT name, age +FROM Person +WHERE CASE + WHEN age IS NULL THEN false + WHEN age < 18 THEN 'minor' + ELSE 'adult' +END = 'adult' +---- + +CASE in MATCH WHERE clause (enum-to-string conversion with pattern matching): + +[source,sql] +---- +MATCH {type: Product, as: prod, + where: ((CASE + WHEN color = 1 THEN 'red' + WHEN color = 2 THEN 'blue' + WHEN color = 3 THEN 'green' + END) ILIKE '%ed%')} +RETURN prod.name +---- + +This is particularly useful for converting enum values (stored as integers) to human-readable strings that can be filtered with wildcards. + +CASE in MATCH RETURN clause: + +[source,sql] +---- +MATCH {type: Person, as: p, where: (age IS NOT NULL)} +RETURN p.name, + CASE + WHEN p.age < 18 THEN 'minor' + WHEN p.age < 65 THEN 'adult' + ELSE 'senior' + END as category +ORDER BY p.name +---- + +Nested CASE expressions: + +[source,sql] +---- +SELECT + name, + CASE + WHEN balance > 0 THEN + CASE + WHEN balance > 10000 THEN 'Premium' + ELSE 'Standard' + END + ELSE 'Overdrawn' + END as accountStatus +FROM Account +---- + +CASE in LET clause: + +[source,sql] +---- +SELECT $category +FROM Product +LET $category = CASE + WHEN price < 10 THEN 'Budget' + WHEN price < 100 THEN 'Standard' + ELSE 'Premium' +END +---- + +CASE with NULL handling: + +[source,sql] +---- +SELECT + name, + CASE + WHEN age IS NULL THEN 'Unknown' + WHEN age < 18 THEN 'Minor' + ELSE 'Adult' + END as status +FROM Person +---- diff --git a/src/main/asciidoc/query-languages/sql/sql-script.adoc b/src/main/asciidoc/query-languages/sql/sql-script.adoc index 58506bde..6015c39a 100644 --- a/src/main/asciidoc/query-languages/sql/sql-script.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-script.adoc @@ -24,9 +24,12 @@ SQL Script supports all the ArcadeDB <>, plus the fol ** `<retry>` is the number of retries in case of concurrent modification exception * `ROLLBACK` * `LET <variable> = <SQL>`, to assign the result of a SQL command to a variable. To reuse the variable prefix it with the dollar sign `$`. +* `SET GLOBAL <variable> = <BOOLEAN|STRING|NUMBER|LIST|MAP>`, to assign a transient global variable. To reuse the variable prefix it with the dollar sign `$`. NOTE: `LOCK` explicitly locks a type or bucket during a transaction until it is committed. +NOTE: A `SET GLOBAL`-declared variable exists as long as the associated database is not closed or the server shut down. + NOTE: A `LET` can be used as an ephemeral https://en.wikipedia.org/wiki/View_(SQL)[view]. NOTE: `LET`-declared variables have dynamic scope. diff --git a/src/main/asciidoc/query-languages/sql/sql-select.adoc b/src/main/asciidoc/query-languages/sql/sql-select.adoc index f90b131c..6c650c96 100644 --- a/src/main/asciidoc/query-languages/sql/sql-select.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-select.adoc @@ -44,10 +44,9 @@ SELECT [ [DISTINCT] ] * *<>* Designates conditions to filter the result-set. * *<>* Binds context variables to use in projections, conditions or sub-queries. * *`GROUP BY`* Designates field on which to group the result-set. -* *`ORDER BY`* Designates the field with which to order the result-set. Use the optional `ASC` and `DESC` operators to define the +* *`ORDER BY`* Designates the field with which to order the result-set. Use the optional `ASC` and `DESC` operators, or `true` (= `ASC`) and `false` (= `DESC`), to define the direction of the order. The default is ascending. Additionally, if you are using a <>, you - need to include the `ORDER BY` field in the projection. Note that ORDER BY works only on projection fields (fields that are - returned to the result set) not on LET variables. + need to include the `ORDER BY` field in the projection. * *<>* Designates the field on which to unwind the collection. * *`SKIP`* Defines the number of records you want to skip from the start of the result-set. You may find this useful in <>, when using it in conjunction with `LIMIT`. * *`LIMIT`* Defines the maximum number of records in the result-set. You may find this useful in <>, when using it in conjunction with `SKIP`. diff --git a/src/main/asciidoc/query-languages/sql/sql-update.adoc b/src/main/asciidoc/query-languages/sql/sql-update.adoc index ba245953..d92932ce 100644 --- a/src/main/asciidoc/query-languages/sql/sql-update.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-update.adoc @@ -12,6 +12,7 @@ Update one or more records in the current database. Remember: ArcadeDB can work UPDATE |BUCKET:| [SET|REMOVE = [,]*]|[CONTENT|MERGE ] [UPSERT] + [APPLY DEFAULTS] [RETURN []] [WHERE ] [LIMIT ] [TIMEOUT ] @@ -25,7 +26,8 @@ UPDATE |BUCKET:| * *`UPSERT`* Updates a record if it exists or inserts a new record if it doesn't. This avoids the need to execute two commands, (one for each condition, inserting and updating). `UPSERT` requires a <> clause and a type target. There are further limitations on `UPSERT`, explained below. Practically `UPSERT` means: `UPDATE` if the `WHERE` condition is fulfilled, otherwise `INSERT`. -* *`RETURN`* Specifies an expression to return instead of the record and what to do with the result-set returned by the expression. The available return operators are: +* `APPLY DEFAULTS` applies a properties' default attribute on an update again. +* `RETURN` Specifies an expression to return instead of the record and what to do with the result-set returned by the expression. The available return operators are: ** `COUNT` Returns the number of updated records. This is the default return operator. ** `BEFORE` Returns the records before the update. ** `AFTER` Return the records after the update. diff --git a/src/main/asciidoc/query-languages/sql/sql-where.adoc b/src/main/asciidoc/query-languages/sql/sql-where.adoc index 1f41927f..d3f8dadb 100644 --- a/src/main/asciidoc/query-languages/sql/sql-where.adoc +++ b/src/main/asciidoc/query-languages/sql/sql-where.adoc @@ -60,6 +60,8 @@ And `item` can be: |any|`+<=>+`|Null-safe-equals, is also true if left and right operands are `+NULL+`|`+name <=> word+` |string|`+LIKE+`|Similar to equals, but allows the wildcards '`+%+`' that means "any characters" and '`+?+`' that means "any single character". `+LIKE+` is case sensitive. Does not use index!|`+name LIKE 'Luk%'+` |string|`+ILIKE+`|Similar to `+LIKE+`, but `+ILIKE+` is case insensitive.|`+name ILIKE 'lUk%'+` +|string|`+NOT LIKE+`|Negation of `+LIKE+`, equivalent to `+NOT (x LIKE y)+`|`+name NOT LIKE 'Leia'+` +|string|`+NOT ILIKE+`|Negation of `+ILIKE+`, equivalent to `+NOT (x ILIKE y)+`|`+name NOT ILIKE 'lEIA'+` |any|`+<+`|Less than|`+age < 40+` |any|`+<=+`|Less or equal to|`+age <= 40+` |any|`+>+`|Greater than|`+age > 40+` diff --git a/src/main/asciidoc/reference/settings.adoc b/src/main/asciidoc/reference/settings.adoc index 743d545b..5742e0b4 100644 --- a/src/main/asciidoc/reference/settings.adoc +++ b/src/main/asciidoc/reference/settings.adoc @@ -140,6 +140,7 @@ The following plugins are available for ArcadeDB Server: |`postgres.debug`|Enables the printing of Postgres protocol to the console. Default is false|Boolean|false |`postgres.host`|TCP/IP host name used for incoming connections for Postgres plugin. Default is '0.0.0.0'|String|0.0.0.0 |`postgres.port`|TCP/IP port number used for incoming connections for Postgres plugin. Default is 5432|Integer|5432 +|`redis.defaultDatabase`|Default database name for Redis protocol connections. If set, RAM commands (SET, GET, etc.) will use this database's globalVariables. Empty means no default (requires SELECT command or key prefix)|String| |`redis.host`|TCP/IP host name used for incoming connections for Redis plugin. Default is '0.0.0.0'|String|0.0.0.0 |`redis.port`|TCP/IP port number used for incoming connections for Redis plugin. Default is 6379|Integer|6379 |`mongo.host`|TCP/IP host name used for incoming connections for Mongo plugin. Default is '0.0.0.0'|String|0.0.0.0 @@ -154,6 +155,7 @@ The following plugins are available for ArcadeDB Server: |`server.httpsIncomingPort`|TCP/IP port number used for incoming HTTPS connections. Specify a single port or a range `-`. Default is 2490-2499 to accept a range of ports in case they are occupied.|String|2490-2499 |`server.httpsIoThreads`|Number of threads to use in the HTTP server|Integer|2 per core |`server.httpTxExpireTimeout`|Timeout in seconds for a HTTP transaction to expire. This timeout is computed from the latest command against the transaction|Long|30 +|`server.httpBodyContentMaxSize`|Maximum size in bytes for HTTP request body content. Set to -1 for unlimited size. Default is 100MB|Integer|100 |`server.mode`|Server mode between 'development', 'test' and 'production'|String|development |`server.name`|Server name|String|ArcadeDB_0 |`server.plugins`|Server plugins to load, see <>. Format as comma separated list of: `:`.|String|