In KDB Q, how can I select the last letter of a symbol? - kdb

Say I have a table with an enumerated symbol column with values:
sym
_ _ _ _
AAPL
MSFT
INTC
I'm trying to select just the rows where the last letter of the symbol is C.
I've selecting against last string sym and -1#string sym, but I get an incompatible list length error every time.
What am I doing wrong?

The keyword like works for symbols as well as strings so no need to cast to string if you're trying to pattern match
q)select from ([]sym:`AAPL`MSFT`INTC`ABC) where sym like"*C"
sym
----
INTC
ABC

Does this work?
q)t: ([] sym: `AAPL`MSFT`INTC)
q)t
sym
----
AAPL
MSFT
INTC
q)select last each string sym from t
sym
---
L
T
C

Related

How do I select by month in KDB?

I have a table of the form
t r v
-------------------------------------------------
2016.01.04D09:51:00.000000000 -0.01507338 576
2016.01.04D09:52:00.000000000 -0.001831502 200
2016.01.04D11:37:00.000000000 -0.001100514 583
2016.01.04D12:04:00.000000000 -0.001653045 1000
I want to get the October 2020 values.
I tried doing a query:
select from x where t.month = 2020.10
but this didn't work. I think I might need to cast a date type? What am I doing wrong?
The trailing m allows the interpreter know that the atom is of month type instead of float type.
q)type 2020.10
-9h
q)type 2020.10m
-13h
q)select from x where t.month=2020.10
t
-
q)select from x where t.month=2020.10m
t
-----------------------------
2020.10.20D20:20:00.000000000

Extracting data from a table in kdb

Kdb question:
They're multiple rows in a table and I want to check if all the rows if the column meets a condition.
So the column StartDay = ***
How can I check each single row for that column?
Select from t where StartDay = '$"***"
Just gives me type errors.
Any help would be appreciated !
Assuming the column StartDay is of date type like in the following example
q)show t:([]StartDay:.z.d+til 3;number:til 3;sym:`abc`def`ghi)
StartDay number sym
---------------------
2021.02.19 0 abc
2021.02.20 1 def
2021.02.21 2 ghi
Then the following query will work
q)select from t where StartDay=2021.02.19
StartDay number sym
---------------------
2021.02.19 0 abc
The example you have given seems like you are trying to query a column of symbol type. Here are two examples of that
q)select from t where sym=`$"ghi"
StartDay number sym
---------------------
2021.02.21 2 ghi
q)select from t where sym=`ghi
StartDay number sym
---------------------
2021.02.21 2 ghi
Perhaps the following guide on where in q-sql will help.

Complex list of list of empty characters in a column in kdb

I have a joined table which consists of list of list of characters.
q)t:([] a:`c`d; b:("";"fill"));
q)s:([] a:`b`c`c; b:("";"";""))
q)select from t lj select b by a from s
Output:
a b
---------
c ("";"") / This is the culprit want to replace it with null character
d "fill"
The output of join consists of a list of list of empty characters.
I want to replace that with empty character.
Expected output:
a b
---------
c ""
d "fill"
Tried: Few Unsuccessful attempts
q)update b:?[null in b;raze b;b]from select from t lj select b by a from s
q)update b:?["" in b;raze b;b]from select from t lj select b by a from s
To replace a list of list of empty strings with empty string, you can try below query:
q) select from t lj select (b;"")all""~/:b by a from s
Output:
a b
--------
c ""
d "fill"
Explanation:
Basically, empty strings list is coming from group command on the right table. So during the grouping stage, we can match if all the items in a grouped list (b column values) for particular a value are an empty string. And if they are just replacing them with a single empty string.
q) select (b;"")all""~/:b by a from s
a| b
-| --
b| ""
c| ""
For a = c , b grouped values are ("";""). Lets break down the command:
q) b:("";"")
q) ""~/:b / output 11b
q) all ""~/:b / output 1b
q)(b;"") all ""~/:b / output ""
The last command is list indexing. If the return from the previous command is 1b which means all items are empty strings, then return "" else return actual b.
Edit:
Based on the discussion in the comment section of TerryLynch's answer, it looks like your requirement is:
if all values of b list after grouping are empty strings then return a single empty string.
if values of b are a mixture of empty strings and non-empty strings, then remove all empty strings.
For that, you could use the below query:
q) select from t lj select b:raze ("";b except enlist "") by a from s
But that would result in different types for different values in b column. An empty string will be 10h and all non-empty string list will be 0h.
For consistent type, can use below query which returns enlist"" instead of "" but that will not be an empty string:
q) select from t lj select b:{(c;enlist "")()~c:x except enlist ""}b by a from s
Instead of trying to fix the adverse outcome I think you need to decide what you want to do with the duplicate c rows in the s table. You're grouping by the a column but it has duplicates so how should it behave .... should it take the first value, should it take the last value? Should it append the two strings together? If you solve that then you avoid this problem, for example:
q)t lj select last b by a from s
a b
--------
c ""
d "fill"
An alternative solution would be to simply raze all the results of b together. Less where clauses in use and less match (~) operations.
q)update raze'/[b] from (t lj select b by a from s)
a b
--------
c ""
d "fill"
Here I've used over to account for more an unknown level of enlistment, as a precaustion, and then applied it to each row from the lj. For your case, an even faster solution would be
update raze each b from (t lj select b by a from s)
This will give different results than Rahuls answers
q)update raze each b from (t lj select b by a from s)
a b
--------
c "str"
d "fill"
q) select from t lj select (b;"")all""~/:b by a from s
a b
------------
c ("";"str")
d "fill"
q)update raze each b from (t lj select b by a from s)
a b
--------
c "str"
d "fill"

q/kdb Selecting a variable in query

q)sym:`a`b`c
q)t:([] s:`g`v; p:2?10.)
Selecting the variable sym works fine in the following query :
q)select sym from t
However it throws an error while selecting with a table column, I am not able to figure out the reason
q)select sym, p from t
You get a 'length error because the lists sym and p (column from t) are different lengths.
q)sym:`a`b
q)select sym,p from t
sym p
------------
a 3.927524
b 5.170911
What is the output you are trying to get to with this?
Assuming you are trying to select as many elements of sym as the table count :
q)select p,(count i)#sym from t
p sym
------------
1.780839 a
3.017723 b

KDB: select rows based on value in one column being contained in the list of another column

very simple, silly question. Consider the following table:
tt:([]Id:`6`7`12 ;sym:`A`B`C;symlist:((`A`B`M);(`X`Y`Z);(`H`F`C)))
Id sym symlist
---------------
6 A `A`B`M
7 B `X`Y`Z
12 C `H`F`C
I would like to select all rows in tt where the element in sym is contained in the list symlist. In this case, it means just the first and third rows. However, the following query gives me a type error.
select from tt where sym in symlist
(`type)
Whats the proper way to do this? Thanks
You want to use the ' (each-both) adverb, so that they "pair up" so to speak. Recall that sym is just list, and symlist is a list of lists. You want to check each element in sym with the respective sub-list in symlist. You do this by telling it to "pair up".
q)tt:([]id:6712; sym:`A`B`C; symlist:(`A`B`M;`X`Y`Z;`H`F`C))
q)select from tt where sym in'symlist
id sym symlist
----------------
6712 A A B M
6712 C H F C
It's not entirely clear to me why your query results in a type error, so I'd be interested in hearing other people's responses.
q)select from tt where sym in symlist
'type
in
`A`B`C
(`A`B`M;`X`Y`Z;`H`F`C)
q)select from tt where {x in y}[sym;symlist]
id sym symlist
--------------
In reponse to JPCs answer (couldn't format this as a comment)....
Type error possibly caused by applying "where" to a scalar boolean
q)(`a`b`c) in (`a`g`b;`u`i`o;`g`c`t)
0b
q)where (`a`b`c) in (`a`g`b;`u`i`o;`g`c`t)
'type
Also, the reason the {x in y} lambda doesn't cause the error is because the "in" is obscured and is not visible to the parser (parser doesn't look inside lambdas)
q)0N!parse"select from tt where {x in y}[sym;symlist]";
(?;`tt;,,({x in y};`sym;`symlist);0b;())
Whereas the parser can "see" the "in" in the first case
q)0N!parse"select from tt where sym in symlist";
(?;`tt;,,(in;`sym;`symlist);0b;())
I'm guessing the parser tries to do some optimisations when it sees the "in"