sqlite3 join query from single table - sql

A sqlite3 db table contains device perf data with two columns.. device and value.
Content is something like this
deviceA|50
deviceB|75
deviceA|125
deviceB|25
deviceA|99
deviceB|10
deviceA|101
and on and on
For each device
I want to know how many entries are in the table (total)
I want to know how mnay entries are over threshold of 100 (overthreshold)
I want to know how many entries are under threshold of 100 (underthreshold)
I want to know the percent of total entries under threshold (percent)
This is my query so far
select distinct(total.device),
total.count,
overthreshold.count,
round(((total.count*1.0 - overthreshold.count)/total.count),4)*100
from
(select device,count(*) as count from perfdata group by device) as total
inner join (
select device,count(*) as count from perfdata where value>100 group by device
) as overthreshold
group by overthreshold.device;
deviceA only results included here
deviceA|2017|16|99.21
deviceA had 2017 entries in the table, 16 of which are > 100; 99.21% under threshold.
for all device/value combinations, output currently only shows those overthreshold as my query tells it to.
deviceB is never overthreshold and isn't in query output (100% under threshold).
Any advice on where/how would I add in the
select device,count(*) as count from perfdata where value<100 group by device
statement to get underthreshold returned back for inclusion in my calculation?
Thanks for any help.

You want to use conditional aggregation. This is where you use the case statement along with the aggregation functions:
select device, count(*) as TotalCount,
sum(case when value > 100 then 1 else 0 end) as OverThreshhold,
sum(case when value < 100 then 1 else 0 end) as UnderThreshhold,
100.0 * avg(case when value < 100 then 1.0 else 0.0 end) as PercentageUnder
from perfdata
group by device;

Related

Select sum and average from table with different condition

I have a PostgreSQL table as shown in screenshot
I want to fetch the following data in same query
Sum of all units
Average of all unit_price only where units > 0
How can I achieve that?
Here is one possible approach (NOTE: I have no access to a PostgreSQL to check syntax, so I'm presenting here a sort of pseudo-code without checking it).
SELECT SUM(UNITS) AS UNITS_SUM ,
SUM(UNIT_PRICE)/POSS_UNITS_COUNT AS AVERAGE_UNIT_PRICE
FROM
(SELECT UNITS AS UNITS ,
CASE WHEN UNITS > 0 THEN 1
ELSE 0
END AS POSS_UNITS_COUNT ,
CASE WHEN UNITS > 0 THEN UNIT_PRICE
ELSE 0
END AS UNIT_PRICE
FROM Your_Table) A ;
Note that this would yield a DIVIDE BY 0 error if no positive price is in your table (I'm assuming that such condition cannot exist; if it does, you should condition the division using a CASE where POSS_UNITS_COUNT must be > 0.
I would just use conditional aggregation. In Postgres, that uses filter:
select sum(units),
avg(unit_price) filter (where units > 0)
from t;

Oracle SQL Column division error

I have this piece of Oracle SQL that has been giving me problems on and off. I have got it to work one time today and then the next time I tried to run it I was given an SQL command not properly ended. All I'm trying to do is divide one column by itself under the 2 different restraints.
SELECT start_end_amt,
in_out_amt
FROM MYTABLE.MYTABLE,
(
SELECT sum(start_end_amt)
FROM MYTABLE.MYTABLE
WHERE in_out_amt = 'C'
) / (
SELECT sum(start_end_amt)
FROM MYTABLE.MYTABLE
WHERE in_out_amt = 'D'
) * 100 AS RATIO
ORDER BY RATIO,
start_end_amt,
in_out_amt
However, now that I run it this way I am getting an error on the *100 part. It's an SQL command not properly ended. As far as I was aware this was the proper way to write a select query.
My expected outcome is to have a table that returns a percent ratio for each transaction that occurs. The one time it did work it was not outputting a percent either unfortunately.
I think you just simply need to group by a transaction ID and do conditional aggregation. Something like this:
select transaction_id,
sum(case when in_out_amt = 'C' then start_end_amt else 0 end) /
sum(case when in_out_amt = 'D' then start_end_amt else 0 end) * 100 RATIO
from MYTABLE.MYTABLE
group by transaction_id

PostgreSQL - Handling empty query result

I am quite new to SQL and I am currently working on some survey results with PostgreSQL. I need to calculate percentages of each option from 5-point scale for all survey questions. I have a table with respondentid, questionid, question response value. Demographic info needed for filtering datacut is retrieved from another table. Then query is passed to result table. All queries texts for specific datacuts are generated by VBA script.
It works OK in general, however there's one problematic case - when there are no respondents for specific cut and I receive empty table as query result. If respondent count is greater than 0 but lower than calculation threshold (5 respondents) I am getting table full of NULLs which is OK. For 0 respondents I get 0 rows as result and nothing is passed to result table and it causes some displacement in final table. I am able to track such cuts as I am also calculating respondent number for overall datacut and storing it in another table. But is there anything I can do at this point - generate somehow table full of NULLs which could be inserted into result table when needed?
Thanks in advance and sorry for clumsiness in code.
WITH ItemScores AS (
SELECT
rsp.questionid,
CASE WHEN SUM(CASE WHEN rsp.respvalue >= 0 THEN 1 ELSE 0 END) < 5 THEN
NULL
ELSE
ROUND(SUM(CASE WHEN rsp.respvalue = 5 THEN 1 ELSE 0 END)/CAST(SUM(CASE
WHEN rsp.respvalue >= 0 THEN 1 ELSE 0 END) AS DECIMAL),2)
END AS 5spercentage,
... and so on for frequencies of 1s,2s,3s and 4s
SUM(CASE WHEN rsp.respvalue >= 0 THEN 1 ELSE 0 END) AS QuestionTotalAnswers
FROM (
some filtering applied here [...]
) AS rsp
GROUP BY rsp.questionid
ORDER BY rsp.questionid;
INSERT INTO results_items SELECT * from ItemScores;
If you want to ensure that the questionid column won't be empty, then you must call a cte with its plain values and then left join with the table that actually you are using to make the aggregations, calcs etc. So it will generate for sure the first list and then join its values.
The example of its concept would be something like:
with calcs as (
select questionid, sum(respvalue) as sum_per_question
from rsp
group by questionid)
select distinct rsp.questionid, calcs.sum_per_question
from rsp
left join calcs on rsp.questionid = calcs.questionid

Multiple aggregate functions in query

I need to have two aggregate functions in my query, but can't figure out how to filter.
I need the number of samples and the number of samples greater than 1.
something like:
SELECT COUNT(Samples), COUNT(Samples >1)
FROM SampleData
I could do a subquery, but is there a better way to filter like this?
You can basically then the value of Sample using CASE and the result of it is the aggregated via SUM().
SELECT COUNT(Samples),
SUM(CASE WHEN Samples > 1 THEN 1 ELSE 0 END)
FROM SampleData
This will work on most RDBMS though.
To get the number of records, see JW's answer. Similarly, to get the total value of samples, and the total value of samples where samples>1, use:
SELECT SUM(Samples) TotalSamples,
SUM(CASE WHEN Samples > 1 THEN Samples ELSE 0 END) SamplesGT1
FROM SampleData
In case you're using PostgreSQL, you can use the standard SQL FILTER clause:
SELECT COUNT(*), COUNT(*) FILTER (WHERE Samples > 1)
FROM SampleData

SQL query to add or subtract values based on another field

I need to calculate the net total of a column-- sounds simple. The problem is that some of the values should be negative, as are marked in a separate column. For example, the table below would yield a result of (4+3-5+2-2 = 2). I've tried doing this with subqueries in the select clause, but it seems unnecessarily complex and difficult to expand when I start adding in analysis for other parts of my table. Any help is much appreciated!
Sign Value
Pos 4
Pos 3
Neg 5
Pos 2
Neg 2
Using a CASE statement should work in most versions of sql:
SELECT SUM( CASE
WHEN t.Sign = 'Pos' THEN t.Value
ELSE t.Value * -1
END
) AS Total
FROM YourTable AS t
Try this:
SELECT SUM(IF(sign = 'Pos', Value, Value * (-1))) as total FROM table
I am adding rows from a single field in a table based on values from another field in the same table using oracle 11g as database and sql developer as user interface.
This works:
SELECT COUNTRY_ID, SUM(
CASE
WHEN ACCOUNT IN 'PTBI' THEN AMOUNT
WHEN ACCOUNT IN 'MLS_ENT' THEN AMOUNT
WHEN ACCOUNT IN 'VAL_ALLOW' THEN AMOUNT
WHEN ACCOUNT IN 'RSC_DEV' THEN AMOUNT * -1
END) AS TI
FROM SAMP_TAX_F4
GROUP BY COUNTRY_ID;
select a= sum(Value) where Sign like 'pos'
select b = sum(Value) where Signe like 'neg'
select total = a-b
this is abit sql-agnostic, since you didnt say which db you are using, but it should be easy to adapat it to any db out there.