Does dolphindb support list query? - sql

I would like to apply the following group of SQL statements at once and union the result to get the most recent record behind mt=52355979 of various stock(idetified by 'symbol') of different trade places and market types(identified by 'c1','c2','c3','c4').
select * from t where symbol=`A,c1=25,c2=814,c3=11,c4=2, date=2020.02.05, mt<52355979 order by mt desc limit 1
select * from t where symbol=`B,c1=25,c2=814,c3=12,c4=2, date=2020.02.05, mt<52355979 order by mt desc limit 1
select * from t where symbol=`C,c1=25,c2=814,c3=12,c4=2, date=2020.02.05, mt<52354979 order by mt desc limit 1
select * from t where symbol=`A,c1=1180,c2=333,c3=3,c4=116, date=2020.02.05, mt<52355979 order by mt desc limit 1
The filter columns in where condition will not change, while the filter values may change each time. Does DolphindB offer querying methods which allow to run list query with varying input parameters?

You can define a function as follows
def bundleQuery(tbl, dt, dtColName, mt, mtColName, filterColValues, filterColNames){
cnt = filterColValues[0].size()
filterColCnt =filterColValues.size()
orderByCol = sqlCol(mtColName)
selCol = sqlCol("*")
filters = array(ANY, filterColCnt + 2)
filters[filterColCnt] = expr(sqlCol(dtColName), ==, dt)
filters[filterColCnt+1] = expr(sqlCol(mtColName), <, mt)
queries = array(ANY, cnt)
for(i in 0:cnt) {
for(j in 0:filterColCnt){
filters[j] = expr(sqlCol(filterColNames[j]), ==, filterColValues[j][i])
}
queries.append!(sql(select=selCol, from=tbl, where=filters, orderBy=orderByCol, ascOrder=false, limit=1))
}
return loop(eval, queries).unionAll(false)
}
and then use the following script
dt = 2020.02.05
dtColName = "dsl"
mt = 52355979
mtColName = "mt"
colNames = `symbol`c1`c2`c3`c4
colValues = [50982208 50982208 51180116 41774759, 25 25 25 1180, 814 814 814 333, 11 12 12 3, 2 2 2 116]
bundleQuery(t, dt, dtColName, mt, mtColName, colValues, colNames)

Related

postgresql Multiple identical conditions are unified into one parameter

I have one sql that need convert string column to array and i have to filter with this column,sql like this:
select
parent_line,
string_to_array(parent_line, '-')
from
bx_crm.department
where
status = 0 and
'851' = ANY(string_to_array(parent_line, '-')) and
array_length(string_to_array(parent_line, '-'), 1) = 5;
parent_line is a varchar(50) column,the data in this like 0-1-851-88
question:
string_to_array(parent_line, '-') appear many times in my sql.
how many times string_to_array(parent_line) calculate in each row. one time or three times
how convert string_to_array(parent_line) to a parameter. at last,my sql may like this:
depts = string_to_array(parent_line, '-')
select
parent_line,
depts
from
bx_crm.department
where
status = 0 and
'851' = ANY(depts) and
array_length(depts, 1) = 5;
Postgres supports lateral joins which can simplify this logic:
select parent_line, v.parents, status, ... other columns ...
from bx_crm.department d cross join lateral
(values (string_to_array(parent_line, '-')) v(parents)
where d.status = 0 and
cardinality(v.parents) = 5
'851' = any(v.parents)
Use a derived table:
select *
from (
select parent_line,
string_to_array(parent_line, '-') as parents,
status,
... other columns ...
from bx_crm.department
) x
where status = 0
and cardinality(parents) = 5
and '851' = any(parents)

Query with equation

I have 3 queries that return 3 values. I'd Like to join the queries to perform the following expression:
(MgO + CaO)/SiO2
How can I do that?
MgO:
SELECT sampled_date, result
FROM AF_VW WHERE element = 'MgO' AND ROWNUM = 1 ORDER BY sampled_date DESC;
CaO:
SELECT sampled_date, result
FROM AF_VW WHERE element = 'CaO' AND ROWNUM = 1 ORDER BY sampled_date DESC;
SiO2:
SELECT sampled_date, result
FROM AF_VW WHERE element = 'SiO2' AND ROWNUM = 1 ORDER BY sampled_date DESC;
with x as (
SELECT sampled_date, result, element,
row_number() over(partition by element order by sampled_date desc) rn
FROM AF_VW)
, y as (
select
case when element = 'MgO' then result end as MGO,
case when element = 'CaO' then result end as CaO,
case when element = 'SiO2' then result end as SiO2
FROM x where rn = 1)
select (mgo+cao)/sio2 from y;
You can use row_number function instead of rownum and then select the results for the 3 elements.
This is a bit long for a comment.
The queries in your question are probably not doing what you expect. Oracle evaluates the WHERE clause before the order by. So, the following chooses one arbitrary row with MgO and then does the trivial ordering of the one row by date:
SELECT sampled_date, result
FROM AF_VW
WHERE element = 'MgO' AND ROWNUM = 1
ORDER BY sampled_date DESC;
Really, to get the equivalent result, you would need to emulate the same, unstable logic. Unstable, because the results are not guaranteed to be the same if the query is run multiple times:
with mg as (
SELECT sampled_date, result
FROM AF_VW
WHERE element = 'MgO' AND ROWNUM = 1
),
coa as (
SELECT sampled_date, result
FROM AF_VW
WHERE element = 'CaO' AND ROWNUM = 1
),
sio2 as (
SELECT sampled_date, result
FROM AF_VW
WHERE element = 'SiO2' AND ROWNUM = 1
)
select (mgo.result + cao.result) / sio2.result
from mgo cross join cao cross join sio2;
I suspect you really want the most recent sample date, which is what VKP's answer provides. I just thought you should know that is not what your current queries are doing.

Getting previous value + new value as a column?

say I have this:
select money from somewhere
I want now another column called accumulatedMoney which is going to be = to accumulatedMoney of previous row + money of current row
Ex:
m = 2, am = 2
m = 3, am = 5
m = 3, am = 8
...
What can I do to achieve this?
Thanks
In any database, you can do this with a correlated subquery:
select t.am, t.m,
(select sum(tprev.m) from t tprev where tprev.am <= t.am) as cumsum
from t
In any database, you can also do this as a join and group by:
select t.am, t.m, sum(tprev.m) as cumsum
from t join
t tprev
on tprev.am <= t.am
group by t.am, t.m
In databases that support cumulative sums, you can do it as:
select t.am, t.m,
sum(t.m) over (order by t.am) as cumsum
from t
(SQL Server 2012 and Oracle support this.)

SQL Subtract first row from all selected rows

Is there a way to subtract the value of the first selected row from all rows ? So if I have
t = 1, v = 500
t = 2, v = 800
t = 3, v = 1200
I would get
t = 1, v = 0
t = 2, v = 300
t = 3, v = 700
I'm always looking for a portable solution but a Postgres solution works just the same :-)
Thank you.
SELECT v - FIRST_VALUE(v) OVER (ORDER BY t)
FROM mytable
ORDER BY
t
Something like this may work
SELECT mt2.t, mt2.v - mt1.v AS v
FROM MyTable mt1
CROSS JOIN MyTable mt2
WHERE mt1.t = 1
Most portable way without using window functions:
select v - first
from
mytable,
(select v as first from mytable order by t limit 1) as inner
order by t

sql select without sort

I guess this is a long shot but, is there a way to list the sql query without sorting...
eg. I have
select * from items
where manufacID = 2
or manufacID = 1
or manufacID = 4
and I don't want them to be listed in the asc or decs order, but as i typed in... so 2,1,4.
So, can i do that?
You could add an extra column in the select as your sort column then order by that:
SELECT
*,
CASE manufacID
WHEN 2 THEN 1
WHEN 1 THEN 2
WHEN 4 THEN 3
END AS sortOrder
FROM
items
ORDER BY
sortOrder
Yes, use this:
SELECT * FROM items
WHERE manufacID IN (2, 1, 4)
ORDER BY (manufacID = 2) ASC,
(manufacID = 1) ASC,
(manufacID = 4) ASC
The results are sorted in the order that the conditions match. Change ASC to DESC to reverse the order. This only works on databases which allow conditions in the sort clauses.
(Side note: why would you want to do this?)
As you haven't specified the sorting, the records will be sorted in the natural order, which depends on the RDBMS you are using. In SQL Server for example the order is undefined.
You can create a value to order by from the values:
select * from items
where manufacID in (2, 1, 4)
order by case manufacID
when 2 then 1
when 1 then 2
when 4 then 3
end
SELECT * FROM
(
select 1 as sort, * from items
where manufacID = 2
union all
select 2 as sort, * from items
where manufacID = 1
union all
select 3 as sort, * from items
where manufacID = 4
)
order by sort
select * from items where manufacID = 2
union all
select * from items where manufacID = 1
union all
select * from items where manufacID = 4