How can I allow users to submit q queries and interpret them as a string? - kdb

I want to allow users to write real q queries like
select from table where date=.z.d
Is it possible to use something like
E)select from table where date=.z.d
and then use the input to that E) to parse the query and do stuff with it?

If you create a function called .E.e, anything you pass to it will be interpreted as a string, so you can do something like this to start parsing your input:
q).E.e: {" " vs x}
q)E)select from table where date = .z.d
"select"
"from"
"table"
"where"
"date"
,"="
".z.d"

Related

How can I query the same column in a kdb table multiple times in a single statement?

I have the following table in kdb...
p:([]r:("(A|A(A|B|C|D).*)";"A(E|F|G|H|I).*";"A(J|K|L|M).*";"A(N|O|P|Q|R|S).*";"A(T|U|V|W|X|Y|Z).*";"B.*";"(C|C(A|B|C|D|E).*)";"C(F|G|H|I|J|K).*";"C(L|M|N|O|P|Q|R).*";"C(S|T|U|V|W|X|Y|Z).*";"D.*"))
r
----------------------
"(A|A(A|B|C|D).*)"
"A(E|F|G|H|I).*"
"A(J|K|L|M).*"
"A(N|O|P|Q|R|S).*"
"A(T|U|V|W|X|Y|Z).*"
"B.*"
"(C|C(A|B|C|D|E).*)"
"C(F|G|H|I|J|K).*"
"C(L|M|N|O|P|Q|R).*"
"C(S|T|U|V|W|X|Y|Z).*"
"D.*"
and the below function that parses each row of the table...
getRange:{$[x like "*(*";
[if[x like "(*"; x2:1#1_x; l:enlist x2; x:-1_(3_x)];
l,:enlist {(3#x),"-",(-3#x)} ssr[ssr[ssr[x;".";""];")";"]"];"(";"["];
if[((count l)>1)&(l[1] like "*A-*"); l[1]:ssr[l[1]; "A-";"0-9/A-"]];
:l];
:enlist ssr[x;".";""]
];
}
Which gives an output like this...
r1:raze getRange'[exec r from p]
q)r1
,"A"
"A[0-9/A-D]*"
"A[E-I]*"
"A[J-M]*"
"A[N-S]*"
"A[T-Z]*"
"B*"
,"C"
"C[0-9/A-E]*"
"C[F-K]*"
"C[L-R]*"
"C[S-Z]*"
"D*"
I'm parsing the rows so they can be inserted into a query similar to something like select from t where sym like raze getRange'[exec r from p][0]
What I'd like to be able to do is combine the first "single A" with the first "group of A" and the same with the C's (so it looks like below). But the problem I'm having is that those results can't be easily inserted into a query...
(,"A";"A[0-9/A-D]*")
,"A[E-I]*"
,"A[J-M]*"
,"A[N-S]*"
,"A[T-Z]*"
,"B*"
(,"C";"C[0-9/A-E]*")
,"C[F-K]*"
,"C[L-R]*"
,"C[S-Z]*"
,"D*"
Is there a way in q that I can do this? Essentially, select from t where sym like (enlist "A";"A[0-9/A-D]*")
Please let me know if you need any additional info. Thank you in advance.
For matching against multiple regexps we can do following
select from t where any sym like/:("A";"A[0-9/A-D]*")

string query in a function in kdb

func:{[query] value query};
query is part of my function. I have add some like delete xxx, yyyy from (value query) and some manipulation. I am not sure why when I don't use value "query", the function doesn't work. It said it cannot find the table. So I have to use value query in the function and query is a parameter. I need to pass "select from tab" to the function.
My questions is: how do I send if the filter is a string too?
func["select from tab where a="abc""] <<< this does not work
How can I make string inside a string work?
Also, not sure why if I do
func["select from tab where date = max date"] it did not work due to length error
but func["100#select from tab where date = max date"] it works ?
The whole function is
getTable:{[query]loadHDB[];.Q.view date where date < .z.D-30;tab:(delete xxxx,yyyyy,sub,ID,subID,tID,subTID,text,gID from((value query)));remove[];update {";"sv #[s;where (s:";"vs x) like "cId=*";:;enlist""]}each eData from (update {";"sv #[s;where (s:";"vs x) like "AId=*";:;enlist""]}each eData from tab)};
remove:{[]delete tab from `.};
loadHDB:{[]value "\\l /hdb};
You can escape the quotes using backslash http://code.kx.com/wiki/Reference/BackSlash#escape
func["select from tab where a like \"abc\""]
Edit:
If tab is a HDB table then this length error could point to a column length issue (which 100# is avoiding). What does the following return?
q)checkPartition:{[dt] a!{c!{count get x} each ` sv' x,/:c:({x where not x like "*#"} key[x])except `.d}each a:(` sv' d,/:key[d:hsym `$string dt])};
q)check:checkPartition last date
q)(where{1<count distinct value x}each check)#check
I like using -3! and also -1 to print the result. If you know what your query should look like if executed from the console then after you construct your string, use -1 to print the string. It should print the query as how it would be executed by the console.
q)stst:-3!
q)"select max age by user from tab where col1 like ",stst"Hello"
"select max age by user from tab where col1 like \"Hello\""
q)/then to view how it will be executed, use -1
q)-1"select max age by user from tab where col1 like ",stst"Hello";
select max age by user from tab where col1 like "Hello"
q)/looks good

Elixir Ecto - PostgreSQL jsonb Functions

I am in the process of converting a Ruby on Rails API over to Elixir and Phoenix. In my Postgres database, I have a table with a jsonb column type. One of the keys in the json is an array of colors. For example:
{"id": 12312312, "colors": ["Red", "Blue", "White"]}
What I am trying to do from Ecto is query my table for all records that contain the colors Red or Blue. Essentially, recreate this query:
select * from mytable where data->'colors' ?| array['Red', 'Blue']
I'm having some difficulties constructing this query with Ecto. Here is what I have:
Note: "value" will be a pipe delimited list of colors
def with_colors(query, value) do
colors = value
|> String.split("|")
|> Enum.map(fn(x) -> "'#{x}'" end)
|> Enum.join(", ")
# colors should look like "'Red', 'Blue'"
from c in query,
where: fragment("data->'colors' \\?| array[?]", ^colors))
end
This is currently not working as expected. I am having issues with the replacement question mark, as it seems to wrap additional quotes around my field. What is the proper way to do this use fragment? Or maybe there is a better way?
I'm going to run into this problem again because I'm also going to have to recreate this query:
select * from mytable where data->'colors' #> '["Red", "Blue"]'
I have found a solution to my problem.
def with_colors(query, value) do
colors = value
|> String.split("|")
from c in query,
where: fragment("data->'colors' \\?| ?", ^colors))
end

Firebird 2.5.x. Extract column names and column datatypes of a result from stored procedure

I have a Firebird 2.5 database .As an example I have stored procedure with a name QRESULT which expected return is:
Parameter - DATATYPE
a - date
b - numeric(18,0)
c - integer
d - varchar(50)
and so on....
I use PHP - PDO to query the firebird database using the procedure QRESULT like this:
SELECT a,b,d from QRESULT() where a = "some value"
I need to run some query before QRESULT procedure and i need it to return the datatype of all the columns that QRESULT would return if it was ran. So i can help user to type proper value for my "where" clause.I know i can set that manually in the user interface, but in the real project there are lots of procedures and if there is a way i can make my filter interface generate dynamically i would be happy about that.If this is not possible for a stored procedure i can make it with select statements.I just need some lead.
The information you want is in the RDB$PROCEDURE_PARAMETERS table, basically what you need is query
SELECT r.RDB$PARAMETER_NAME ParName, F.RDB$FIELD_TYPE ParType
FROM RDB$PROCEDURE_PARAMETERS r
JOIN RDB$FIELDS F ON(F.RDB$FIELD_NAME = R.RDB$FIELD_SOURCE)
WHERE r.RDB$PROCEDURE_NAME = 'QRESULT'
AND r.RDB$PARAMETER_TYPE = 1
ORDER BY r.RDB$PARAMETER_TYPE, r.RDB$PARAMETER_NUMBER
Note that the SP name should be in upper case as this is how it is stored into system tables (unless you use quoted identifiers). If you want to get both input and output parameters the delete the r.RDB$PARAMETER_TYPE = 1 predicate from the WHERE (type 0 is input parameters and 1 is output).
The type returned by this query is integer id for the type, quick googling found this:
14,"TEXT "
7,"SHORT "
8,"LONG "
9,"QUAD "
10,"FLOAT "
27,"DOUBLE "
35,"TIMESTAMP "
37,"VARYING "
261,"BLOB "
40,"CSTRING "
45,"BLOB_ID "
12,"DATE "
13,"TIME "
16,"INT64 "
but if you want to have more precise type then see this SO post.

Scala Play Framework Anorm SQL.on disable wrapping replacements with ' '

Whenever I replace placeholders in the SQL query using on it surrounds the replacement with '', is there a way to prevent this?
It means I can't do things like
SQL("SELECT * FROM {table} blah").on("table" -> tabletouse)
because it wraps the table name with '' which causes an SQL syntax error.
you could certainly combine both approaches, using the format function for data you don't want to be escaped
SQL(
"""
select %s from %s
where
name = {name} and
date between {start} and {end}
order by %s
""".format(fields, table, order)
).on(
'name -> name,
'start -> startDate,
'end -> endDate
)
Just take into account that the data you are sending using the format function should NOT come from user input, otherwise it should be properly sanitized
You cannot do what you are trying. Anorm's replacement is based on PreparedStatements. Meaning all data will automatically be escaped, meaning you cannot use replacement for :
table names,
column names,
whatever operand, SQL keyword, etc.
The best you can do here is a String concatenation (and what is really a bad way in my opinion) :
SQL("SELECT * FROM " + tabletouse + " blah").as(whatever *)
PS : Checkout this question about table names in PreparedStatements.