SQL Server - Creating Filtered Indexes - sql-server-2008

I have a table with a dateTime column on which I want to put a filtered index. This index will get rebuilt each week. Each time it's rebuilt, I want it to include rows two days old and newer, based on this column. Can I create such a filtered index? I've tried various approaches and I get syntax errors.
For example, the following Where clause on the index creation did not work:
WHERE (ReadTime > DateAdd(dd,-2,GetDate()))

You can't do this by referencing getdate() directly. You would need dynamic SQL.
The CREATE INDEX grammar only allows comparisons against a constant.
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON <object> ( column [ ASC | DESC ] [ ,...n ] )
[ INCLUDE ( column_name [ ,...n ] ) ]
[ WHERE <filter_predicate> ]
... /*Irrelevant grammar removed*/
<filter_predicate> ::=
<conjunct> [ AND <conjunct> ]
<conjunct> ::=
<disjunct> | <comparison>
<disjunct> ::=
column_name IN (constant ,...n)
<comparison> ::=
column_name <comparison_op> constant
<comparison_op> ::=
{ IS | IS NOT | = | <> | != | > | >= | !> | < | <= | !< }

Related

jq select compare two max's of array within object

Let's say I have to following JSON file:
{
"1.1.1.1": {
"history_ban": [
"2021-05-02 14:30",
"2022-01-01 12:00"
],
"history_unban": [
"2021-05-09 14:30",
"2022-01-08 12:00"
]
},
"2.2.2.2": {
"history_ban": [
"2022-01-16 07:00"
],
"history_unban": []
},
"3.3.3.3": {
"history_ban": [
"2022-01-15 22:40"
]
}
}
My goals is to get all the keys where:
Max history_ban date is smaller than "2022-01-16 09:00"
Max history_unban date is empty/non-existent or smaller then Max history_ban date
I believe I have the majority of the query working as I wanted, but the 'Compare max unban with max ban' is not working. My current (not working) query is as follows:
to_entries[] | select((.value.history_ban != null) and (.value.history_ban | max < "2022-01-16 09:00") and ((.value.history_unban | length == 0 ) or (.value.history_unban | max < .value.history_ban | max))) | .key
I know my error is within (.value.history_unban | max < .value.history_ban | max) because, if I replace it with (.value.history_unban | max < "somedate") I get a working query.
The error I get is
jq: error (at :22): Cannot index array with string "value"
exit status 5
What do I need to do to select/compare these two max values?
Just to be sure, my expected result in this example is
"2.2.2.2"
"3.3.3.3"
You could use the update operator // to introduce another constraint if history_unban is existent and not empty.
jq -r '
to_entries[] | select(.value
| (.history_ban | max) as $maxban
| $maxban > "2022-01-16 09:00"
and (.history_unban | length == 0 // $maxban > max)
).key
'
2.2.2.2
3.3.3.3
Demo

Json hash save into relational database in rows and columns

I want to read the values from json and need to create a new json so is there any way that
we can save json in table and columns in oracle that will help to perform calculation on that. calculation is too complax.
Here is the json sample and json has many hash and
{
"agri_Expense": {
"input": 6000,
"max": 7500,
"check": 7500
},
"income3": {
"Hiring_income": 239750
},
"Operational_Cost1": [
{
"Field_input3": 10000,
"Minimum": "0.05",
"Check_Input": 26750,
"Tractor_Cost": "Maintenance"
}
]
}
You do not need PL/SQL, and can do it entirely in SQL.
I want to read the values from json [...] so is there any way that
we can save json in table and columns in oracle
Yes, use SQL to create a table:
CREATE TABLE table_name ( json_column CLOB CHECK ( json_column IS JSON ) )
and then INSERT the value there:
INSERT INTO table_name ( json_column ) VALUES (
'{'
|| '"agri_Expense": {"input": 6000,"max": 7500,"check": 7500},'
|| '"income3": {"Hiring_income": 239750},'
|| '"Operational_Cost1": [{"Field_input3": 10000,"Minimum": "0.05","Check_Input": 26750,"Tractor_Cost": "Maintenance"}]'
|| '}'
)
then, if you want individual values, SELECT using JSON_TABLE:
SELECT j.*
FROM table_name t
CROSS JOIN JSON_TABLE(
t.json_column,
'$'
COLUMNS (
agri_expense_input NUMBER PATH '$.agri_Expense.input',
agri_expense_max NUMBER PATH '$.agri_Expense.max',
agri_expense_check NUMBER PATH '$.agri_Expense.check',
income3_hiring_income NUMBER PATH '$.income3.Hiring_income',
NESTED PATH '$.Operational_Cost1[*]'
COLUMNS (
oc1_field_input3 NUMBER PATH '$.Field_input3',
oc1_minimum NUMBER PATH '$.Minimum',
oc1_check_input NUMBER PATH '$.Check_Input'
)
)
) j
Which outputs:
AGRI_EXPENSE_INPUT | AGRI_EXPENSE_MAX | AGRI_EXPENSE_CHECK | INCOME3_HIRING_INCOME | OC1_FIELD_INPUT3 | OC1_MINIMUM | OC1_CHECK_INPUT
-----------------: | ---------------: | -----------------: | --------------------: | ---------------: | ----------: | --------------:
6000 | 7500 | 7500 | 239750 | 10000 | .05 | 26750
db<>fiddle here

Higher cardinality column first in an index when involving a range?

CREATE TABLE `files` (
`did` int(10) unsigned NOT NULL DEFAULT '0',
`filename` varbinary(200) NOT NULL,
`ext` varbinary(5) DEFAULT NULL,
`fsize` double DEFAULT NULL,
`filetime` datetime DEFAULT NULL,
PRIMARY KEY (`did`,`filename`),
KEY `fe` (`filetime`,`ext`), -- This?
KEY `ef` (`ext`,`filetime`) -- or This?
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
There are a million rows in the table. The filetimes are mostly distinct. There are a finite number of ext values. So, filetimehas a high cardinality and ext has a much lower cardinality.
The query involves both ext and filetime:
WHERE ext = '...'
AND filetime BETWEEN ... AND ...
Which of those two indexes is better? And why?
First, let's try FORCE INDEX to pick either ef or fe. The timings are too short to get a clear picture of which is faster, but `EXPLAIN shows a difference:
Forcing the range on filetime first. (Note: The order in WHERE has no impact.)
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(fe)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
| 1 | SIMPLE | files | range | fe | fe | 14 | NULL | 16684 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-----------------------+
Forcing the low-cardinality ext first:
mysql> EXPLAIN SELECT COUNT(*), AVG(fsize)
FROM files FORCE INDEX(ef)
WHERE ext = 'gif' AND filetime >= '2015-01-01'
AND filetime < '2015-01-01' + INTERVAL 1 MONTH;
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
| 1 | SIMPLE | files | range | ef | ef | 14 | NULL | 538 | Using index condition |
+----+-------------+-------+-------+---------------+------+---------+------+------+-----------------------+
Clearly, the rows says ef is better. But let's check with the Optimizer trace. The output is rather bulky; I'll show only the interesting parts. No FORCE is needed; the trace will show both options then pick the better.
...
"potential_range_indices": [
...
{
"index": "fe",
"usable": true,
"key_parts": [
"filetime",
"ext",
"did",
"filename"
]
},
{
"index": "ef",
"usable": true,
"key_parts": [
"ext",
"filetime",
"did",
"filename"
]
}
],
...
"analyzing_range_alternatives": {
"range_scan_alternatives": [
{
"index": "fe",
"ranges": [
"2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 16684,
"cost": 20022, <-- Here's the critical number
"chosen": true
},
{
"index": "ef",
"ranges": [
"gif <= ext <= gif AND 2015-01-01 00:00:00 <= filetime < 2015-02-01 00:00:00"
],
"index_dives_for_eq_ranges": true,
"rowid_ordered": false,
"using_mrr": false,
"index_only": false,
"rows": 538,
"cost": 646.61, <-- Here's the critical number
"chosen": true
}
],
...
"attached_conditions_computation": [
{
"access_type_changed": {
"table": "`files`",
"index": "ef",
"old_type": "ref",
"new_type": "range",
"cause": "uses_more_keyparts" <-- Also interesting
}
}
With fe (range column first), the range could be used, but it estimated scanning through 16684 rows fishing for ext='gif'.
With ef (low cardinality ext first), it could use both columns of the index and drill down more efficiently in the BTree. Then it found an estimated 538 rows, all of which are useful for the query -- no further filtering needed.
Conclusions:
INDEX(filetime, ext) used only the first column.
INDEX(ext, filetime) used both columns.
Put columns involved in = tests first in the index regardless of cardinality.
The query plan won't go beyond the first 'range' column.
"Cardinality" is irrelevant for composite indexes and this type of query.
("Using index condition" means that the Storage Engine (InnoDB) will use columns of the index beyond the one used for filtering.)

SQL Server JSON_VALUE syntax

I created a SQL Server Table with 25 columns. One of my columns is actually JSON text, stored as nvarchar(max).
Now I need to able to query this JSON column and parse out the various attributes. I have tried applying JSON_VALUE to my column but am doing something wrong; my query runs but returns NULL for all the values.
The JSON itself looks like:
[
{
"lineName":"GHjr",
"pipeDiameter":"12",
"pipeLength":"52000",
"pressure":"15",
"volume":"107"
},
{
"lineName":"Ks3R",
"pipeDiameter":"9",
"pipeLength":"40000",
"pressure":"15",
"volume":"80"
}
]
The SQL I am using is:
select
DOC_ID, LINE_SPECS,
JSON_VALUE(LINE_SPECS, '$.lineName') as line_name,
JSON_VALUE(LINE_SPECS, '$.pipe_Diameter') as diameter
from dbo.MY_TEST_DOCS
where ISJSON(LINE_SPECS) > 0
and len(LINE_SPECS) > 3
However, my 2 "parsed" columns are returning all NULL. How do I parse the five attributes from this column?
Without the [] ISJSON is returning false
With [] ISJSON retuns true
Without the [] JSON_VALUE returns NULLs
With [] JSON_VALUE returns values
dbfddle.uk has sql server 2016 available....
create table test (LINE_SPECS nvarchar(max));
insert into test values (N'
{
"lineName":"GHjr",
"pipeDiameter":"12",
"pipeLength":"52000",
"pressure":"15",
"volume":"107"
},
{
"lineName":"Ks3R",
"pipeDiameter":"9",
"pipeLength":"40000",
"pressure":"15",
"volume":"80"
}
');
select *
from test
where ISJSON(LINE_SPECS) > 0
;
GO
| LINE_SPECS |
| :--------- |
select
JSON_VALUE(LINE_SPECS, '$.lineName') as line_name
, JSON_VALUE(LINE_SPECS, '$.pipeDiameter') as diameter
from test
;
GO
line_name | diameter
:-------- | :-------
GHjr | 12
dbfiddle here

Postgres: Nested Aggregate JSON

The table I'm querying looks like this:
namespace | key | value
---------------------------
foo | bar | baz
foo | alpha | beta
gamma | delta | epsilon
And I'd like to pull it out of the database like this:
{
"foo": {
"bar": "baz",
"alpha": "beta"
},
"gamma": {
"delta": "epsilon"
}
}
Playing around with json_object_agg isn't really getting me past the first level, since you're not allowed to nest aggregate functions. But as far as I can see, I need a GROUP BY within a GROUP BY, but I'm not sure if that's possible. Perhaps the solution has to do with WINDOWs?
with t (namespace, key, value) as (
values
('foo','bar','baz'),('foo','alpha','beta'),('gamma','delta','epsilon')
), s as (
select namespace, json_object_agg(key, value) as joa
from t
group by namespace
)
select json_object_agg(namespace, joa)
from s
;
json_object_agg
------------------------------------------------------------------------------------
{ "foo" : { "bar" : "baz", "alpha" : "beta" }, "gamma" : { "delta" : "epsilon" } }
As a CTE is an optimization barrier this version might be faster:
with t (namespace, key, value) as (
values
('foo','bar','baz'),('foo','alpha','beta'),('gamma','delta','epsilon')
)
select json_object_agg(namespace, joa)
from (
select namespace, json_object_agg(key, value) as joa
from t
group by namespace
) s