SQLITE Edge detection - sqlite

I have a given SQLIt database (so no chance to do it in a better way):
CREATE TABLE `history` (
`TIMESTAMP` TIMESTAMP,
`DEVICE` `enter code here`varchar(32),
`TYPE` varchar(32),
`EVENT` varchar(512),
`READING` varchar(32),
`VALUE` varchar(32),
`UNIT` varchar(32)
);
In this table I have for example the following data:
DEVICE VALUE
d1 1
d5 500
d2 10
d1 2 <--
d5 501
d1 100 <---
I want to figure out for the device "d1" all timestamps where the difference between the last value and the current value is > 10
I have absolutly no idea how to do this with SQL
thank you

To get the last value for the current timestamp T, you would use a query like this:
SELECT Value
FROM History
WHERE Device = '...'
AND Timestamp < T
ORDER BY Timestamp DESC
LIMIT 1;
You can then use this as a correlated subquery in your query:
SELECT Timestamp
FROM History
WHERE Device = 'd1'
AND ABS((SELECT Value
FROM History AS last
WHERE Device = 'd1' -- or Device = History.Device
AND last.Timestamp < History.Timestamp
ORDER BY Timestamp DESC
) - Timestamp) > 10;

Related

Can't get top nth records sorted on value in Cosmos DB

I am trying to get the top 5 records ordered on a specific value in Cosmos DB but I am getting stuck at getting the records ordered.
The query is done on the following document:
{
"id": string,
"Compliant": bool,
"DefinitionId": int,
"DefinitionPeriod": string,
"EventDate": date,
"HerdProfileId": int,
"Period": int,
"Value": int
}
What i have tried:
1st try
SELECT TOP 5 cr.HerdProfileId, cr.Compliant, cr.NonCompliant, cr.NullCompliant FROM (
SELECT
c.HerdProfileId,
SUM(comp) as Compliant,
SUM(noncomp) as NonCompliant,
SUM(nullcomp) as NullCompliant
FROM c
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = true) comp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = false) noncomp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = null) nullcomp
WHERE c.Period = 201948
GROUP BY c.HerdProfileId) cr
WHERE cr.NonCompliant > 0
ORDER BY cr.NonCompliant
results in: Unsupported ORDER BY clause. ORDER BY item expression could not be mapped to a document path
2nd try:
SELECT TOP 5 cr.HerdProfileId, cr.Compliant, cr.NonCompliant, cr.NullCompliant FROM (
SELECT
c.HerdProfileId,
SUM(comp) as Compliant,
SUM(noncomp) as NonCompliant,
SUM(nullcomp) as NullCompliant
FROM c
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = true) comp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = false) noncomp
JOIN(SELECT VALUE COUNT(c.id) FROM c WHERE c.Compliant = null) nullcomp
WHERE c.Period = 201950
GROUP BY c.HerdProfileId
ORDER BY NonCompliant DESC) cr
WHERE cr.NonCompliant > 0
results in: ORDER BY' is not supported in presence of GROUP BY
Is there any way to get the data needed or is this just not possible in Cosmos DB and do I need to order the results in code later on?
The first sql: Order by item expression could not be mapped to a document path. Please refer to the statements in this blog:
The second sql:
Order by can't work with Group By so far,please refer to official statement:
I suppose that you have to follow the suggestions in my previous case:How to group by and order by in cosmos db? you order the results in code so far. Waiting for the plan of above 2rd statement for group by and order by...

Teradata SQL - Convert values separated by ; in a single column to multiple rows

I have a single column with comma separated values like below.
sel job_dependency from test_table;
job_dependency
1;2;3;4;5;6
I need to convert it into below format in Teradata SQL where each number is a row.
job_dependency
1
2
3
4
5
6
Any help would be really helpful.
There's a table function for this task:
WITH cte AS
(
SELECT
1 AS inKey -- might be a column, either INT or VarChar up to 60 bytes
-- Other data types should be CASTed to VarChar (and back in the Select)
,job_dependency2 AS inString
FROM test_table
)
SELECT *
FROM TABLE
( StrTok_Split_To_Table(cte.inKey, cte.inString, ';')
RETURNS (outKey INTEGER, -- data type must match input column
tokenNum INTEGER,
token VARCHAR(20))
) AS dt

How can I accumulate values from rows on a per closest date basis to a list of dates as a parameter according the parameter dates?

There is table that has a date and cnt column e.g.
timestamp cnt
------------------
1547015021 14
1547024080 2
This table can be created using :-
DROP TABLE IF EXISTS roundit_base;
CREATE TABLE IF NOT EXISTS roundit_base (timestamp INTEGER, cnt INTEGER);
INSERT INTO roundit_base VALUES (1547015021,14),(1547024080,2);
The result should be the sum of the cnt column of rows that are the closest timestamp to a list of supplied timestamps, e.g. the supplied data could be
1546905600 - 0
1546992000 - 0
1547078400 - 0
...
The result should be along the lines of
1546905600 - 0
1546992000 - 14
1547078400 - 2
That is two columns:-
the timestamp from the list of supplied timestamps, that the respective rows from the database are closest to and
the sum of the cnt column those rows on a per supplied timestamp
Although the results are different from the expected results in that the calculations used places both 1547015021 and 1547024080 as being closest to the suplied timestamp of 1546992000;
The following could be the basis of an SQLite based solution :-
WITH
-- The supplied list of timestamps
v (cv,dflt) AS (
VALUES (1546905600,0),(1546992000,0),(1547078400,0)
),
-- Join the two sets calculating the difference
cte1 AS (
SELECT *, abs(cv - timestamp) AS diff FROM roundit_base INNER JOIN v
),
-- Find the closest (smallest difference) for each timestamp
cte2 AS (
SELECT *, min(diff) FROM cte1 GROUP BY timestamp
)
-- For each compartive value sum the counts allocated/assigned (timestamps) to that
SELECT cv,
CASE
WHEN
(SELECT sum(cnt) FROM cte2 WHERE cv = v.cv) IS NOT NULL
THEN
(SELECT sum(cnt) FROM cte2 WHERE cv = v.cv)
ELSE 0
END AS cnt
FROM v;
;
The above results in :-

query with max and second factor [duplicate]

I have:
TABLE MESSAGES
message_id | conversation_id | from_user | timestamp | message
I want:
1. SELECT * WHERE from_user <> id
2. GROUP BY conversation_id
3. SELECT in every group row with MAX(timestamp) **(if there are two same timestamps in a group use second factor as highest message_id)** !!!
4. then results SORT BY timestamp
to have result:
2|145|xxx|10000|message
6|1743|yyy|999|message
7|14|bbb|899|message
with eliminated
1|145|xxx|10000|message <- has same timestamp(10000) as message(2) belongs to the same conversation(145) but message id is lowest
5|1743|me|1200|message <- has message_from == me
example group with same timestamp
i want from this group row 3 but i get row 2 from query
SELECT max(message_timestamp), message_id, message_text, message_conversationId
FROM MESSAGES
WHERE message_from <> 'me'
GROUP BY message_conversationId
ORDER by message_Timestamp DESC
what is on my mind to do union from message_id & timestamp and then get max???
Your query is based on non-standard use of GROUP BY (I think SQLite allows that only for compatibility with MySQL) and I'm not at all sure that it will produce determinate results all the time.
Plus it uses MAX() on concatenated columns. Unless you somehow ensure that the two (concatenated) columns have fixed widths, the results will not be accurate for that reason as well.
I would write the query like this:
SELECT
m.message_timestamp,
m.message_id,
m.message_text,
m.message_conversationId
FROM
( SELECT message_conversationId -- for every conversation
FROM messages as m
WHERE message_from <> 'me'
GROUP BY message_conversationId
) AS mc
JOIN
messages AS m -- join to the messages
ON m.message_id =
( SELECT mi.message_id -- and find one message id
FROM messages AS mi
WHERE mi.message_conversationId -- for that conversation
= mc.message_conversationId
AND mi.message_from <> 'me'
ORDER BY mi.message_timestamp DESC, -- according to the
mi.message_id DESC -- specified order
LIMIT 1 -- (this is the one part)
) ;
Try below sql to achieve your purpose by group by twice.
select m.*
from
Messages m
-- 3. and then joining to get wanted output columns
inner join
(
--2. then selecting from this max timestamp - and removing duplicates
select conversation_id, max(timestamp), message_id
from
(
-- 1. first select max message_id in remainings after the removal of duplicates from mix of cv_id & timestamp
select conversation_id, timestamp, max(message_id) message_id
from Messages
where message <> 'me'
group by conversation_id, timestamp
) max_mid
group by conversation_id
) max_mid_ts on max_mid_ts.message_id = m.message_id
order by m.message_id;
http://goo.gl/MyZjyU
ok it was more simple than I thought:
basically to change select from:
max(message_timestamp)
to:
max(message_timestamp || message_id)
or max(message_timestamp + message_id)
so it will search for max on concatenation of timestamp and message_id
ps. after a digging - it's working only if message id is growing with timestamp ( order of insertion is preserved )
edit:
edit2 :
so why it works ?
SELECT max(message_timestamp+message_id), message_timestamp, message_id, message_conversationId, message_from,message_text
FROM MESSAGES
WHERE message_conversationId = 1521521
AND message_from <> 'me'
ORDER by message_Timestamp DESC

ORDER BY with bool > date > null in SQLite

I have a loooooooooooong SELECT ending with a ORDER BY that can include the following values :
checked (1 or 0)
date (YYYY-MM-DD)
time (HH:MM:SS)
I'd like to order the result of the query the following way :
|__checked = 0
| |__ date ASC
| |__ time ASC
| |__ date && time are null
|__checked = 1
|__ date ASC
|__ time ASC
|__ date && time are null
For now, I got something simple like "ORDER BY i1.checked, date, time" but the trouble is with this the items with empty date and times stay on the top.
Here is the whole query if you ever think you need all the data to find a proper solution. Don't scream.
SELECT i1._id AS _id, i1.title AS title, i1.checked AS checked,
// count the children (-1 is because the closure table include a relation between any item and itself)
(count( c1.item_id ) - 1) AS children_count,
// count the unchecked children
(SELECT (COUNT(DISTINCT i2._id) )
FROM item AS i2 JOIN closure AS c2 ON (i2._id = c2.item_id)
WHERE c2.ancestor_id = i1._id
AND i2.checked = 0
AND c2.item_id NOT IN (0, i1._id)) AS unchecked_children_count,
// get the closest deadlines among the children :
// if there is a date but no time, time is set to 00:00:00
// if there is a time but not date, date is set to today
// if there is no date nor time, both are set to an empty string
// date
ifnull(nullif((SELECT ifnull(nullif(i3.date, ""), date()) AS subdate
FROM item AS i3 JOIN closure AS c3 ON (i3._id = c3.item_id)
WHERE c3.ancestor_id = i1._id
AND (i3.date OR i3.time)
ORDER By subdate, ifnull(nullif(i3.time, ""), "00:00:00")
LIMIT 1), ""), "") AS date,
// time
ifnull(nullif((SELECT ifnull(nullif(i4.time, ""), "00:00:00") AS subtime
FROM item AS i4 JOIN closure AS c4 ON (i4._id = c4.item_id)
WHERE c4.ancestor_id = i1._id
AND (i4.date OR i4.time)
ORDER By ifnull(nullif(i4.date, ""), date()), subtime
LIMIT 1), ""), "") AS time
FROM item AS i1 JOIN closure AS c1 ON ( i1._id = c1.ancestor_id )
WHERE i1.parent_id = 0
AND c1.item_id != 0
GROUP BY c1.ancestor_id
ORDER BY i1.checked, date, time
The items are organised in a tree with a parent_id and a closure table.
ORDER BY il.checked,
CASE WHEN date IS NULL AND time IS NULL THEN 1 ELSE 0 END,
date, time
You could create an extra temp column in a wrapped select around all your sql to allow you to add an artificial order.
SELECT
EACH_COLUMN
, ...
, CASE WHEN DATECol IS NULL AND TimeCol is NULL THEN 0
WHEN TimeCol is NULL THEN 1
WHEN DATECol IS NULL THEN 2
ELSE 3 END As ORDERCOL...
FROM
(
INNER MESS OF ALL THE STUFF IN YOUR QUERY
)
ORDER BY
ORDERCol DESC --Preserves order of BothCols Populated, Null Dates Next, Null Times Next, Both Nulls Last
, Checked
, Date
, Time

Resources