Sum of field with where condition of this field - Influxdb - sum

I want to get the sum of result_code where result_code=0.
What I found is that querying without sum gives me result but adding the aggregation sum() and then I have 0 as a result.
For those who want an understanding of the use case :
I use telegraf to ping some internal IP address to check it's availability (pings every 10s with a timeout of 5s) and I want to get its uptime (result_code=0) per day.
I have tried changing the field in the sum function but that doesn't work better.
SELECT sum("result_code") FROM "ping" WHERE ("url" = 'MyUrl') AND time >= 1557957600000ms and result_code=0
name: ping
time sum
---- ---
1557957600000000000 0
name: ping
time result_code
---- -----------
1557988031000000000 0
1557988040000000000 0
...
In my example I expect to have
name: ping
time sum
---- ---
1557957600000000000 2

It sounds like you want COUNT, rather than the SUM of a collection of zero values.

Related

How to check changes in column values?

I need to try to check some device IDs for work. These are values (15 characters, random string of numbers+letters) that mostly remain constant for users. However, every now and then these deviceIDs will change. And I'm trying to detect when they do change. Is there a way to write this kind of a dynamic query with SQL? Say, perhaps with a CASE statement?
user
device
date
1
23127dssds1272d
10-11
1
23127dssds1272d
10-11
1
23127dssds1272d
10-12
1
23127dssds1272d
10-12
1
04623jqdnq3000x
10-12
Count distinct device by id having count > 1?
Consider below approach
select *
from your_table
where true
qualify device != lag(device, 1, '') over(partition by user order by date)
if applied to sample data in your question - output is
As you can see here - at 10-11 first 'change, assignment' happened for user=1 ; and then on 10-12 he device changed

Query smallest number of rows to match a given value threshold

I would like to create a query that operates similar to a cash register. Imagine a cash register full of coins of different sizes. I would like to retrieve a total value of coins in the fewest number of coins possible.
Given this table:
id
value
1
100
2
100
3
500
4
500
5
1000
How would I query for a list of rows that:
has a total value of AT LEAST a given threshold
with the minimum excess value (value above the threshod)
in the fewest possible rows
For example, if my threshold is 1050, this would be the expected result:
id
value
1
100
5
1000
I'm working with postgres and elixir/ecto. If it can be done in a single query great, if it requires a sequence of multiple queries no problem.
I had a go at this myself, using answers from previous questions:
Using ABS() to order by the closest value to the threshold
Select rows until a sum reduction of a single column reaches a threshold
Based on #TheImpaler's comment above, this prioritises minimum number of rows over minimum excess. It's not 100% what I was looking for, so open to improvements if anyone can, but if not I think this is going to be good enough:
-- outer query selects all rows underneath the threshold
-- inner subquery adds a running total column
-- window function orders by the difference between value and threshold
SELECT
*
FROM (
SELECT
i.*,
SUM(i.value) OVER (
ORDER BY
ABS(i.value - $THRESHOLD),
i.id
) AS total
FROM
inputs i
) t
WHERE
t.total - t.value < $THRESHOLD;

more than one row in subquery percentage

SELECT
status, date(time),
round((SELECT count(*)
FROM log
WHERE status NOT LIKE '200 OK'
GROUP BY date(time)
ORDER BY date(time)) /
(SELECT count(*)
FROM log
GROUP BY date(time)
ORDER BY date(time))) * 100 AS percent
FROM
log
GROUP BY
date(time), status, percent
ORDER BY
date(time);
I already written a code for it but, there is no response, I am using postgreSQL.
The final thing i want is to find THE ERROR PERCENTAGE STATUS(see the status colounm which have 200 Ok or not found) FOR EACH DAY.
FOR EG-- 2016/07/22 - 1.5% ERROR
P.S the database is really big with different status and dates, i want result date wise
In above code i am trying to find the (NOT-FOUND status/Total Status) for each day
Issues with the existing query:
the way you've solved it so far require the table "log" to be scanned 3 times causing huge performance cost
in here >> WHERE status NOT LIKE '200 OK' << you are looking exact value match "200 OK" not pattern match, so you can drop using LIKE and use either NOT() like that >> WHERE NOT status = '200 OK' OR <> operator like that: WHERE status <> '200 OK'
in order to divide higher number from lower, you need to cast your integer to numeric
For latter quick example:
SELECT 1 / 10; -- results to 0
SELECT 1::numeric / 10; -- results to 0.10000000000000000000
Solution
To solve all mentioned and improve query and get expected result (if I did understand expected result correctly) then using WINDOW function this can be solved with query as simple as:
-- The query
SELECT date(time),
round(
(count(1) FILTER (WHERE NOT status = '200 OK'))::numeric * 100 / count(1),
1
) AS errors_rate
FROM log
GROUP BY 1
ORDER BY 1;
-- Should return something like this:
time | errors_rate
------------+------------
2016-07-05 | 1.2
2016-07-06 | 1.3
2016-07-07 | 1.5
...
Some helpful reads:
PG Docs: Aggregate Expressions
PG Docs: Window functions
"The FILTER clause in Postgres 9.4" by Anderson Dias
Compare the date inside the subqueries with the date outside (they should be the same), or you'll be counting for every date.

PostgreSQL: order by column, with specific NON-NULL value LAST

When I discovered NULLS LAST, I kinda hoped it could be generalised to 'X LAST' in a CASE statement in the ORDER BY portion of a query.
Not so, it would seem.
I'm trying to sort a table by two columns (easy), but get the output in a specific order (easy), with one specific value of one column to appear last (got it done... ugly).
Let's say that the columns are zone and status (don't blame me for naming a column zone - I didn't name them). status only takes 2 values ('U' and 'S'), whereas zone can take any of about 100 values.
One subset of zone's values is (in pseudo-regexp) IN[0-7]Z, and those are first in the result. That's easy to do with a CASE.
zone can also take the value 'Future', which should appear LAST in the result.
In my typical kludgy-munge way, I have simply imposed a CASE value of 1000 as follows:
group by zone, status
order by (
case when zone='IN1Z' then 1
when zone='IN2Z' then 2
when zone='IN3Z' then 3
.
. -- other IN[X]Z etc
.
when zone = 'Future' then 1000
else 11 -- [number of defined cases +1]
end), zone, status
This works, but it's obviously a kludge, and I wonder if there might be one-liner doing the same.
Is there a cleaner way to achieve the same result?
Postgres allows boolean values in the ORDER BY clause, so here is your generalised 'X LAST':
ORDER BY (my_column = 'X')
The expression evaluates to boolean, resulting values sort this way:
FALSE (0)
TRUE (1)
NULL
Since we deal with non-null values, that's all we need. Here is your one-liner:
...
ORDER BY (zone = 'Future'), zone, status;
Related:
Sorting null values after all others, except special
Select query but show the result from record number 3
SQL two criteria from one group-by
I'm not familiar postgreSQL specifically, but I've worked with similar problems in MS SQL server. As far as I know, the only "nice" way to solve a problem like this is to create a separate table of zone values and assign each one a sort sequence.
For example, let's call the table ZoneSequence:
Zone | Sequence
------ | --------
IN1Z | 1
IN2Z | 2
IN3Z | 3
Future | 1000
And so on. Then you simply join ZoneSequence into your query, and sort by the Sequence column (make sure to add good indexes!).
The good thing about this method is that it's easy to maintain when new zone codes are created, as they likely will be.

SQL Custom Sorting Bandwidth Data

Beloved SO Cronies,
I'm trying to custom sort bandwidth data using ORDER BY or any performance-focused solution likely involving a temp table. I've scoured SO and Google and have only turned up parts of functions that I can use, so I've arrived at posting here as a final stop.
Data (example)
VALUE
---------
10 Kbps
5 Kbps
1 Mbps
10 Mbps
100 Mbps
10 Gbps
1 Gbps
SQL fiddle with the below. Can you hear it playing in the background?
Bandwidth Sorting Start (SQL Fiddle)
select * from Bandwidth
order by (
case
when Value like '%kbps%' then 1
when Value like '%mbps%' then 2
when Value like '%gbps%' then 3
else 4
end)
My thinking is splitting the string Value into a parameter and running a case on the metric type (e.g. Kbps, Mbps) then applying a multiplier to the parameter based on that and presenting that in a temp table that I can sort and return on an int-based sort without showing the column in the results!
Thanks in advance. I tried to post on DBA StackExchange but existing work location presently blocks the login creation there.
Just use a delimiter to separate the numbers and convert them to integer
order by
(
case
when Value like '%Kbps%' then 1
when Value like '%Mbps%' then 2
when Value like '%Gbps%' then 3
else 4
end) ,
CONVERT(INT,SUBSTRING(Value, 0, CHARINDEX(' ', Value)))
FIDDLE