How to apply max function for each row in KDB? - kdb

I want to ensure all values in column x are no smaller than 0.5, so I do:
update x:max (x 0.5) from myTable
But this gives an error (in Studio For KDB+):
An error occurred during execution of the query.
The server sent the response:
type
Studio Hint: Possibly this error refers to wrong type, e.g `a+1
What's wrong?

You can try using |
q)update x|0.5 from myTable

It should work. It worked for me. This is the query I used for testing:
update x:max(x;0.5) from myTable
-- Check semicolon in max function

Try the kdb vector conditional its similar to case-when in SQL:
q)t:([] a:6?.9)
q)t
a
---------
0.4237094
0.5712045
0.8705158
0.2075746
0.8549775
0.3951729
q)update ?[a<0.5;0.5;a] from t
a
---------
0.5
0.5712045
0.8705158
0.5
0.8549775
0.5
q)

Related

Inclusive intervals don't work as expected in jooq and postgres

When using the jooq-postgres-extension and inserting a row with a field value IntegerRange.integerRange(10, true, 20, true) in the query it is translated by cast('[10,20]' as int4range).
It's interesting that if I run the query select cast('[10,20]' as int4range) I get [10,21) which is not an inclusive interval anymore.
My problem is: when I read the row back in Jooq the integerRange.end is now 21 and not 20.
Is this a known issue and is there a workaround rather than the obvious subtracting 1 to upper boundary?
From here Range Types:
The built-in range types int4range, int8range, and daterange all use a canonical form that includes the lower bound and excludes the upper bound; that is, [). User-defined range types can use other conventions, however.
So the cast transforms '[10,20]' to '[10,21)'.
You can do:
select upper_inc(cast('[10,20]' as int4range));
upper_inc
-----------
f
to test the upper bound for inclusivity and modify:
select upper(cast('[10,20]' as int4range));
upper
-------
21
accordingly.
The jOOQ 3.17 RANGE type support (#2968) distinguishes between
discrete ranges (e.g. DateRange, IntegerRange, LongRange, LocaldateRange)
non-discrete ranges (e.g. BigDecimalRange, LocalDateTimeRange, OffsetDateTimeRange, TimestampRange)
Much like in PostgreSQL, jOOQ treats these as the same:
WITH r (a, b) AS (
SELECT '[10,20]'::int4range, '[10,21)'::int4range
)
SELECT a, b, a = b
FROM r;
The result being:
|a |b |?column?|
|-------|-------|--------|
|[10,21)|[10,21)|true |
As you can see, PostgreSQL itself doesn't distinguish between the two identical ranges. While jOOQ maintains the information you give it, they're the same value in PostgreSQL. PostgreSQL itself won't echo back [10,20]::int4range to jOOQ, so you wouldn't be able to maintain this value in jOOQ.
If you need the distinction, then why not use BigDecimalRange instead, which corresponds to numrange in PostgreSQL:
WITH r (a, b) AS (
SELECT '[10,20]'::numrange, '[10,21)'::numrange
)
SELECT a, b, a = b
FROM r;
Now, you're getting:
|a |b |?column?|
|-------|-------|--------|
|[10,20]|[10,21)|false |

How to fix "ERROR: aggregate functions are not allowed in UPDATE"

I am trying to update a column based on a few conditions, using a calculation.
The theory I am using is as follows;
If column1 contains 'string' then 'calculation of column2 and column3' gets put in column4.
The calculation works, but I am struggling to find a way to UPDATE a column by using these IF conditions and a SUM.
I have searched stack and postgres documentation. I see that there are a number of aggregate errors but none specifically solve this problem.
UPDATE table1
SET "column4" = CASE
WHEN "column1" ILIKE '%Y%' THEN SUM(CAST("column2" AS
numeric(4,2))) / SUM(CAST("column3" AS numeric(4,2)))
END;
The error which I am getting is as follows;
ERROR: aggregate functions are not allowed in UPDATE
LINE 7: WHEN "column1" ILIKE '%Y%' THEN (SUM(CAST("...
Perform your calculations in a Common Table Expression:
WITH cte_avg AS (
SELECT SUM(CAST("column2" AS numeric(4,2))) / SUM(CAST("column3" AS numeric(4,2))) AS avg
FROM table1
)
UPDATE table1
SET "column4" = cte_avg.avg
FROM cte_avg
WHERE "column1" LIKE '%Y%'

Querying date/time on 2 columns

I have a column date and column time on my PostgreSQL table. I wish to make a query, to filter rows that are not expired based on date and time. I tried this, but it does not works and returns an error Postgrex.Error) ERROR 42601 (syntax_error) syntax error at or nea:
from q in Line, where: fragment("date ? + time ? > NOW()", q.date, q.time)
I think this problem can be solved by not using time and date prefixes:
from q in Line, where: fragment("? + ? > NOW()", q.date, q.time)
or even
from q in Line, where: q.date + q.time < fragment("NOW()")
Provided, your columns have the correct data type
not sure if you need to run a standard query or if you are filtering via some GUI, but time and date types can be combined together via simple addition. https://www.postgresql.org/docs/current/functions-datetime.html
The following code:
WITH q AS (
SELECT* FROM (VALUES
('11:29:10'::time,'03-18-2019'::date),
('11:29:10'::time,'03-18-2021'::date)
) t ("time","date")
)
SELECT * FROM q WHERE q.time+q.date > NOW()
Should only print the date in the future, which is what you are trying to achieve.
Hope this helps!

upsert into unkeyed kdb table

I am trying to modify the entry in the factor column that corresponds to the provided date.
I cannot find any good documentation for KDB's upsert function and I have zero idea what I am doing wrong here..
query: {[table;dates;factors] table upsert (date:dates factor:factors);}
table: `test
dates: (2016.01.04T01:30:00.000; 2016.01.04T01:31:00.000)
factors: (0.9340078471263533; 0.9340078471263533)
query[table; dates; factors]
date price original factor askVol bidVol
-----------------------------------------------------------------------
....
2017.04.19T07:28:00.000 6.105 6.105 1 2.176407e+07 1.907746e+07
2017.04.19T07:29:00.000 6.105 6.105 1 2.274138e+07 1.893807e+07
2017.04.19T07:30:00.000 6.105 6.105 1 2.629207e+07 2.030017e+07
....
An error occurred during execution of the query.
The server sent the response:
type
Studio Hint: Possibly this error refers to wrong type, e.g `a+1
You have a small syntax error in the function query, when you define the table from the input arguments -
query: {[table;dates;factors] table upsert (date:dates factor:factors);}
Should be:
query:{[table;dates;factors] table upsert ([] date:dates; factor:factors);}
Note the additional [] after the opening ( for a table definition. Moreover, column values need to be delimited with ;
q)show table:([] dates:.z.D+til 3;factors:3?.1; something:3?`2)
dates factors something
-------------------------------
2017.04.20 0.09441671 hj
2017.04.21 0.07833686 lh
2017.04.22 0.04099561 mg
q)show factormap:(.z.D,.z.D+2)!10000.1 20000.2
2017.04.20| 10000.1
2017.04.22| 20000.2
q)update factors:factors^factormap[dates]from table
dates factors something
-------------------------------
2017.04.20 10000.1 hj
2017.04.21 0.07833686 lh
2017.04.22 20000.2 mg
q)

PostgreSQL doesn't update/copy boolean from subselect?

Here's a short code sample that behaves unexpectedly for me in PostgreSQL v9.5:
create table test (a boolean, b boolean);
insert into test (a) values ('true'),('true'),('true'),('true'),('true');
update test set b = rand.val from (select random() > 0.5 as val from test) as rand;
I expect column b to take on random true/false values, but for some reason it's always false. If I run the subselect of:
select random() > 0.5 as val from test;
It returns random true/false combinations as I want. But for some reason once I try to update the actual table it fails. I've tried several casting combinations but it doesn't seem to help.
What am I missing here?
How about:
update test set b = (random() > 0.5);