Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 192 additions & 0 deletions docs/en/sql-reference/functions/json-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,198 @@ JSONExtractRaw(json [, indices_or_keys]...)
SELECT JSONExtractRaw('{"a": "hello", "b": [-100, 200.0, 300]}', 'b') = '[-100, 200.0, 300]';
```

### Case-Insensitive JSONExtract Functions

The following functions perform case-insensitive key matching when extracting values from JSON objects. They work identically to their case-sensitive counterparts, except that object keys are matched without regard to case.

> These functions may be less performant than their case-sensitive counterparts, so use the regular JSONExtract functions if possible.

### JSONExtractIntCaseInsensitive {#jsonextractintcaseinsensitive}

Parses JSON and extracts a value of Int type using case-insensitive key matching.

**Syntax**

```sql
JSONExtractIntCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractIntCaseInsensitive('{"Value": 123}', 'value') = 123
SELECT JSONExtractIntCaseInsensitive('{"VALUE": -456}', 'Value') = -456
```

### JSONExtractUIntCaseInsensitive {#jsonextractuintcaseinsensitive}

Parses JSON and extracts a value of UInt type using case-insensitive key matching.

**Syntax**

```sql
JSONExtractUIntCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractUIntCaseInsensitive('{"COUNT": 789}', 'count') = 789
```

### JSONExtractFloatCaseInsensitive {#jsonextractfloatcaseinsensitive}

Parses JSON and extracts a value of Float type using case-insensitive key matching.

**Syntax**

```sql
JSONExtractFloatCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractFloatCaseInsensitive('{"Price": 12.34}', 'PRICE') = 12.34
```

### JSONExtractBoolCaseInsensitive {#jsonextractboolcaseinsensitive}

Parses JSON and extracts a boolean value using case-insensitive key matching.

**Syntax**

```sql
JSONExtractBoolCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractBoolCaseInsensitive('{"IsActive": true}', 'isactive') = 1
```

### JSONExtractStringCaseInsensitive {#jsonextractstringcaseinsensitive}

Parses JSON and extracts a string using case-insensitive key matching.

**Syntax**

```sql
JSONExtractStringCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractStringCaseInsensitive('{"ABC": "def"}', 'abc') = 'def'
SELECT JSONExtractStringCaseInsensitive('{"User": {"Name": "John"}}', 'user', 'name') = 'John'
```

### JSONExtractCaseInsensitive {#jsonextractcaseinsensitive}

Parses JSON and extracts a value of the given ClickHouse data type using case-insensitive key matching.

**Syntax**

```sql
JSONExtractCaseInsensitive(json [, indices_or_keys...], return_type)
```

**Example**

```sql
SELECT JSONExtractCaseInsensitive('{"Number": 123}', 'number', 'Int32') = 123
SELECT JSONExtractCaseInsensitive('{"List": [1, 2, 3]}', 'list', 'Array(Int32)') = [1, 2, 3]
```

### JSONExtractKeysAndValuesCaseInsensitive {#jsonextractkeysandvaluescaseinsensitive}

Parses key-value pairs from JSON using case-insensitive key matching.

**Syntax**

```sql
JSONExtractKeysAndValuesCaseInsensitive(json [, indices_or_keys...], value_type)
```

**Example**

```sql
SELECT JSONExtractKeysAndValuesCaseInsensitive('{"Name": "Alice", "AGE": 30}', 'String')[1] = ('Name', 'Alice')
```

### JSONExtractRawCaseInsensitive {#jsonextractrawcaseinsensitive}

Returns part of the JSON as an unparsed string using case-insensitive key matching.

**Syntax**

```sql
JSONExtractRawCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractRawCaseInsensitive('{"Object": {"key": "value"}}', 'OBJECT') = '{"key":"value"}'
```

### JSONExtractArrayRawCaseInsensitive {#jsonextractarrayrawcaseinsensitive}

Returns an array with elements of JSON array, each represented as unparsed string, using case-insensitive key matching.

**Syntax**

```sql
JSONExtractArrayRawCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractArrayRawCaseInsensitive('{"Items": [1, 2, 3]}', 'ITEMS') = ['1', '2', '3']
```

### JSONExtractKeysAndValuesRawCaseInsensitive {#jsonextractkeysandvaluesrawcaseinsensitive}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make a difference for these extract functions to be case insensitive as well?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically went for any JSONExtract function that accepted a path.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, somehow missed that this accepts a path as well 🙈


Extracts raw key-value pairs from JSON using case-insensitive key matching.

**Syntax**

```sql
JSONExtractKeysAndValuesRawCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractKeysAndValuesRawCaseInsensitive('{"Name": "Alice", "AGE": 30}')[1] = ('Name', '"Alice"')
```

### JSONExtractKeysCaseInsensitive {#jsonextractkeyescaseinsensitive}

Parses a JSON string and extracts the keys using case-insensitive key matching to navigate to nested objects.

**Syntax**

```sql
JSONExtractKeysCaseInsensitive(json [, indices_or_keys]...)
```

**Example**

```sql
SELECT JSONExtractKeysCaseInsensitive('{"Name": "Alice", "AGE": 30}') = ['Name', 'AGE']
SELECT JSONExtractKeysCaseInsensitive('{"User": {"name": "John", "AGE": 25}}', 'user') = ['name', 'AGE']
```

**Implementation Notes**

- When multiple keys match with different cases, the first match is returned
- Case-insensitive matching only applies to object keys, not to array indices or the extracted values
- The comparison is ASCII case-insensitive

### JSONExtractArrayRaw {#jsonextractarrayraw}

Returns an array with elements of JSON array, each represented as unparsed string. If the part does not exist or isn't an array, then an empty array will be returned.
Expand Down
1 change: 1 addition & 0 deletions src/Common/JSONParsers/DummyJSONParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct DummyJSONParser
static Iterator end() { return {}; }
static size_t size() { return 0; }
bool find(std::string_view, Element &) const { return false; } /// NOLINT
bool findCaseInsensitive(std::string_view, Element &) const { return false; } /// NOLINT

#if 0
/// Optional: Provides access to an object's element by index.
Expand Down
28 changes: 28 additions & 0 deletions src/Common/JSONParsers/RapidJSONParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <base/defines.h>
#include <rapidjson/document.h>
#include <Common/JSONParsers/ElementTypes.h>
#include <Common/StringUtils.h>

namespace DB
{
Expand Down Expand Up @@ -126,6 +127,33 @@ struct RapidJSONParser
return true;
}

bool findCaseInsensitive(std::string_view key, Element & result) const
{
// RapidJSON doesn't have native case-insensitive search, so we iterate
for (auto it = ptr->MemberBegin(); it != ptr->MemberEnd(); ++it)
{
std::string_view member_key(it->name.GetString(), it->name.GetStringLength());
if (member_key.size() == key.size())
{
bool match = true;
for (size_t i = 0; i < key.size(); ++i)
{
if (!equalsCaseInsensitive(member_key[i], key[i]))
{
match = false;
break;
}
}
if (match)
{
result = it->value;
return true;
}
}
}
return false;
}

/// Optional: Provides access to an object's element by index.
ALWAYS_INLINE KeyValuePair operator[](size_t index) const
{
Expand Down
10 changes: 10 additions & 0 deletions src/Common/JSONParsers/SimdJSONParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,16 @@ struct SimdJSONParser
return true;
}

bool findCaseInsensitive(std::string_view key, Element & result) const
{
auto x = object.at_key_case_insensitive(key);
if (x.error())
return false;

result = x.value_unsafe();
return true;
}

/// Optional: Provides access to an object's element by index.
KeyValuePair operator[](size_t index) const
{
Expand Down
Loading
Loading