Oracle. How to calculate % in one select - plsql

Good afternoon, can you help me?
I have a table of "routes"
Me need calculate count all routes, and count routes with "where". And % two from one.
For example:
select count(routes) from table1 "~ 150000 items"
select count (routes) from table1 where distance < 100 "~ 15000 items"
How to get a number 10%?

You could conditionally aggregate values:
select sum(case when distance < 100 then 1 else 0 end) /
count(*) * 100 as result
from table1;
Or (worse), use current queries as subqueries:
select
(select count(routes) from table1 where distance < 100) /
(select count(routes) from table1) * 100 as result
from dual;

Try this:
select count(CASE WHEN distance < 100 THEN 1 ELSE 0 END)/count(routes)*100 from table1 where distance < 100

Related

group by time interval

Assume I have a table like
how can I create a table like
where the groups are created of timeintervals with the length of 1 second.
Thank you in advance!
Here is an idea, but you need a table of numbers
select (m.startts + n.n - 1) as starttime,
(m.startts + n.n) as enddtime,
sum(case when vehicle_type = 'bus' then 1 else 0 end) as bus,
sum(case when vehicle_type = 'car' then 1 else 0 end) as car
from (select min(Timestamp) as startts from table t) m cross join
(select 1 as n union all select 2 union all select 3) n left join
table t
on t.timestamp >= m.startts + n.n - 1 and
t.timestamp < m.startts + n.n
group by m.startts + n.n;
This is a little dangerous because of the floating point arithmetic, but it will probably work for your purposes.

SQLite count(*) in while clause

I have a calendar table in which there are all the dates in the future and a workday field:
fld_date / fld_workday
2014-01-01 / 1
2014-01-02 / 1
2014-01-03 / 0
...
I want select a date which are n workday far from another date. I tried two ways, but i failed:
The 5th workday from 2014-11-07:
1.
SELECT n1.fld_date FROM calendar as n1 WHERE n1.fld_workday=1 AND
(select count(*) FROM calendar as n2 WHERE n2.fld_date>='2014-11-07' AND n2.fld_workday=1)=5
It gave back 0 row.
2.
SELECT fld_date FROM calendar WHERE fld_date>='2014-11-07' AND fld_workday=1 LIMIT 1 OFFSET 5
It's ok, but i would like to change the 5 days constant to a field, and it's cannot (it would be inside a bigger select statement):
SELECT fld_date FROM calendar WHERE fld_date>='2014-11-07' AND fld_workday=1 LIMIT 1 OFFSET fld_another_field
Any suggestion?
In the first query, the subquery does not refer to the row in n1.
You need a correlated subquery:
SELECT fld_Date
FROM Calendar AS n1
WHERE fld_WorkDay = 1
AND (SELECT COUNT(*)
FROM Calendar AS n2
WHERE fld_Date BETWEEN '2014-11-07' AND n1.fld_Date
AND fld_WorkDay = 1
) = 5
LIMIT 1
The subquery is extremly inefficient if there is no index on the fld_Date column.
You can avoid executing the subquery for every row in n1 by adding another condition with an estimate of the result date (assuming that there are between about four to five work days per week, and using a few extra days to be sure):
...
WHERE fldDate BETWEEN date('2014-11-07', (5 * 4/7 - 10) || ' days')
AND date('2014-11-07', (5 * 5/7 + 10) || ' days')
AND fldWorkDay = 1
AND (SELECT ...

SQL Server 2012 query to compute calculations

I am building a query within SQL Server that is calculating scores we receive for our surveys. We have a column called overall_score, where the user inputs a number from 1-5 as a rating. I am trying to create a stored procedure that will calculate ratings based off the scores.
Score rating = (Total count of scores 4 and 5)/(Total number of responses) * 100
I have three separate select statements that create results I need, but when I go to combine them together my output is 0.
Can someone please guide me on what I am doing wrong here?
Separate SQL Statements:
SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 4;
SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 5;
SELECT count(overall_score) FROM Layer1_DataMerge;
Combined together:
SELECT distinct
(
(
(SELECT count(overall_score) FROM Layer1_DataMerge WHERE Overall_Score = 4) +
(SELECT count(overall_score) FROM Layer1_DataMerge WHERE overall_score = 5)
) / (SELECT count(overall_score) FROM Layer1_DataMerge)
) AS CSAT
FROM Layer1_DataMerge;
Well the reason you're getting zero is because you're doing integer division. With integer division 1/3 = 0. You need to convert to floating-point arithmetic, plus you can do it all in one query:
SELECT 100.0 *
(SUM(CASE WHEN overall_score = 4 THEN 1 ELSE 0 END) +
SUM(CASE WHEN overall_score = 5 THEN 1 ELSE 0 END)) /
COUNT(overall_score)
or
SELECT 100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
To only show 2 decimals you can either cast to a numeric type with 2 decimals:
SELECT CAST(
100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
AS NUMERIC(5,2))
Or use STR to convert to a string:
SELECT STR(
100.0 *
SUM(CASE WHEN overall_score IN (4,5) THEN 1 ELSE 0 END) /
COUNT(overall_score)
,5,2)

Count if function in nested sql query

I have following query in sql server 2005 with a table
select t1.id, CONVERT(VARCHAR,t1.dt,103) date_1, CONVERT(VARCHAR,t2.dt,103) date_2, t1.hotel,
t1.price price_1, t2.price price_2, t2.price - t1.price difference, ((t2.price - t1.price)/t1.price)*100 as Diff_percentage
from test t1
inner join
(
select *
from test
) t2
on t1.hotel = t2.hotel
and t1.dt < t2.dt and t2.dt=(SELECT MAX(dt) from TEST) and t1.dt=(SELECT MAX(dt-1) from TEST)
I want to use count if function within this query. Based on difference column. So that i can count "How many increased, How many decreased, How many same, How many unavailable"
COUNT IF Difference>0 //How many increased
COUNT IF Difference<0 //How many decreased
COUNT IF Difference=0 //How many same
COUNT IF Difference="" //How many unavailable --Difference is blank.
DEMO : http://sqlfiddle.com/#!3/b6f37/29
If I wanted your existing query result I would rewrite the query as:
select t1.id,
CONVERT(VARCHAR,t1.dt,103) date_1,
CONVERT(VARCHAR,t2.dt,103) date_2,
t1.hotel,
t1.price price_1,
t2.price price_2,
t2.price - t1.price difference,
((t2.price - t1.price)/t1.price)*100 as Diff_percentage
from test t1
join (select max(dt) maxDt from test) d
on t1.dt = d.maxDt-1
join test t2
on t2.hotel = t1.hotel
and t2.dt = d.maxDt
To extend your original query to include hotels with missing rows:
select t1.id,
CONVERT(VARCHAR,t1.dt,103) date_1,
CONVERT(VARCHAR,t2.dt,103) date_2,
h.hotel,
t1.price price_1,
t2.price price_2,
t2.price - t1.price difference,
((t2.price - t1.price)/t1.price)*100 as Diff_percentage
from (select distinct hotel from test) h
cross join (select max(dt) maxDt from test) d
left join test t1
on t1.hotel = h.hotel
and t1.dt = d.maxDt-1
left join test t2
on t2.hotel = h.hotel
and t2.dt = d.maxDt
The above query would be much more efficient with a normalized HOTEL table (1 row per hotel) to replace the SELECT DISTINCT subquery.
To get your requested result, I would use:
select count(case when (t2.price-t1.price) < 0 then 1 end) decrease_count,
count(case when (t2.price-t1.price) > 0 then 1 end) increase_count,
count(case when (t2.price-t1.price) = 0 then 1 end) same_count,
count(distinct t1.hotel) - count(case when (t2.price-t1.price) is not null then 1 end) unavailable_count
from test t1
left join (select max(dt) maxDt from test) d
on t1.dt = d.maxDt-1
left join test t2
on t2.hotel = t1.hotel
and t2.dt = d.maxDt
Again the above would be more efficient with a normalized HOTEL table. I would restructure the query more like the previous one: select from HOTEL cross joined to the MAX date query, then outer join to the TEST table twice for the data for the 2 dates. The unavailable count could then be measured more directly, counting the number of rows where the difference computation is NULL.
Here is the SQL Fiddle for all the queries, along with some extended test data.
This approach uses your query and then just summarizes the results:
with t as (
select t1.id, CONVERT(VARCHAR,t1.dt,103) as date_1,
CONVERT(VARCHAR,t2.dt,103) as date_2,
t1.hotel,
t1.price as price_1, t2.price as price_2,
t2.price - t1.price as difference,
((t2.price - t1.price)/t1.price)*100 as Diff_percentage
from test t1 join
test t2
on t1.hotel = t2.hotel and
t1.dt < t2.dt and
t2.dt=(SELECT MAX(dt) from TEST) and
t1.dt=(SELECT MAX(dt-1) from TEST)
)
select sum(case when diff_percentage > 0.0 then 1 else 0 end) as numIncrease,
sum(case when diff_percentage < 0.0 then 1 else 0 end) as numDecrease,
sum(case when diff_percentage = 0.0 then 1 else 0 end) as numSame,
sum(case when diff_percentage is NULL then 1 else 0 end) as numBlank
from t
I'm not sure what "dt - 1" means. With date/datetime values in SQL Server, one usually uses "dateadd(day, -1, )" to subtract a date. In any case, there may be other ways to calculate what you want, but this answers your specific question.

Group by not returning 0 value

My table contains pk_id,reviewer_id,rating.
There are 4 type of rating.
1-very good.
2-good.
3-bad.
4-very bad.
I want to calculate how much rating given by each reviewer.
Means:
If Akee having id 200 has given 2 very good,4 good,3 bad and zero very bad rating to different code.
I want result
count--- rate
2---------1
4---------2
3---------3
0---------4
My query is
SELECT COUNT(RATE),RATE
FROM CODE_REVIEW WHERE CODE_REVIEWER_ID= 200
GROUP BY RATE;
It is showing result
count--- rate
2---------1
4---------2
3---------3
I want to show the fourth row that is 4 rating zero.
How can it be done??
If Rate is not the primary key in another table then you need define your own list of rates so MySQL knows what the permutations of rate are:
SELECT Rates.Rate,
COUNT(Code_Review.Rate) AS CountOfRate
FROM ( SELECT 1 AS Rate UNION ALL
SELECT 2 AS Rate UNION ALL
SELECT 3 AS Rate UNION ALL
SELECT 4
) AS Rates
LEFT JOIN Code_Review
ON Code_Review.Rate = Rates.Rate
AND CODE_REVIEWER_ID = 200
GROUP BY Rates.Rate
Try this query:
SELECT coalesce(c.cnt, 0), r.rate
FROM (SELECT 1 AS rate UNION ALL SELECT 2
UNION ALL SELECT 3 UNION ALL SELECT 4) AS r
LEFT JOIN (SELECT COUNT(RATE),RATE
FROM CODE_REVIEW WHERE CODE_REVIEWER_ID= 200
GROUP BY RATE) AS c
ON r.rate = c.rate;
The first subquery creates a list of possible rates. You can avoid it if you have a table which defines all rates;
Second subquery is yours;
LEFT JOIN guarantees that all rates will be shown;
coalesce() is needed to convert NULL into 0.
Assuming that you do not have a separate table where the rates are defined.
SElECT * from (
SELECT distinct(m.rate), countrate from code_review m
LEFT JOIN
(SELECT COUNT(rate) as countrate,rate FROM code_review
WHERE code_reviewer_id=200 GROUP BY rate) t
ON m.rate=t.rate) a
You could do it somthing like this
SELECT
rates.RATE
, SUM(COUNT) COUNT
FROM
(
SELECT 1 RATE, 0 COUNT UNION ALL
SELECT 2 RATE, 0 COUNT UNION ALL
SELECT 3 RATE, 0 COUNT UNION ALL
SELECT 4 RATE, 0 COUNT
) Rates
LEFT JOIN
(
SELECT
RATE
, COUNT(RATE) COUNT
FROM
CODE_REVIEW
WHERE
CODE_REVIEWER_ID= 200
GROUP BY RATE
) Ratings200
ON Ratings200.RATE = Rates.RATE
If you can, you should push to try to get it in column format as it is simple as:
SELECT
SUM(rate = 1) AS 1,
SUM(rate = 2) AS 2,
SUM(rate = 3) AS 3,
SUM(rate = 4) AS 4
FROM
code_review
WHERE
code_reviewer_id = 200
But if you really need a row format, you could do:
SELECT
a.rate,
COUNT(b.rate) AS cnt
FROM
(
SELECT 1 AS rate UNION ALL
SELECT 2 AS rate UNION ALL
SELECT 3 AS rate UNION ALL
SELECT 4 AS rate
) a
LEFT JOIN
code_review b ON a.rate = b.rate AND code_reviewer_id = 200
GROUP BY
a.rate
SELECT
Rate,
totCount
FROM
(
Select
Rate,
count(Rate) as totCount
from
Code_Review
where
CODE_REVIEWER_ID = 200
group by
Rate
union
select 4, 0
union
select 3, 0
union
select 2, 0
union
select 1, 0
) AS T
group by
T.Rate

Resources