I have t-sql as follows:
SELECT (COUNT(Intakes.fk_ClientID) * 100) / (
SELECT count(*)
FROM INTAKES
WHERE Intakes.AdmissionDate >= #StartDate
)
FROM Intakes
WHERE Intakes.fk_ReleasedFromID = '1'
AND Intakes.AdmissionDate >= #StartDate;
I'm trying to get the percentage of clients who have releasedfromID = 1 out of a subset of clients who have a certain range of admission dates. But I get rows of 1's and 0's instead. Now, I can get the percentage if I take out the where clauses, it works:
SELECT (COUNT(Intakes.fk_ClientID) * 100) / (
SELECT count(*)
FROM INTAKES
)
FROM Intakes
WHERE Intakes.fk_ReleasedFromID = '1';
works fine. It selects ClientIDs where ReleasedFromID =1, multiplies it by 100 and divides by total rows in Intakes. But how do you run percentage with WHERE clauses as above?
After reading comment from #Anssssss
SELECT (COUNT(Intakes.fk_ClientID) * 100.0) / (
SELECT count(*)
FROM INTAKES
) 'percentage'
FROM Intakes
WHERE Intakes.fk_ReleasedFromID = '1';
Related
I have a postgres table A where I am looking to query n rows above and below a certain chosen value in a column.
I have already implemented two basic queries as shown below
SELECT * FROM A
WHERE a >= 100
AND a <= 100+n
and
SELECT * FROM A
WHERE a <= 100
AND a >= 100-n
Is there a way to merge these two queries into 1 instead of having to define two separate queries?
Naively just put both conditions in the where clause and link them with OR:
SELECT * FROM A
WHERE ( a >= 100 AND a <= 100+n )
OR (a <= 100 AND a >= 100-n )
but that will probably perform badly.
with a union,
SELECT * FROM A
WHERE a >= 100
AND a <= 100+n
UNION -- use UNION ALL here if you want two copies of all a=100 rows
SELECT * FROM A
WHERE a <= 100
AND a >= 100-n
Or by reasoning about ordered values and noting that the conditions specify ranges on a and noticing that they overlap.
SELECT * FROM A
WHERE a >= 100-n
AND a <= 100+n
this can also be rewritten as
SELECT * FROM A
WHERE a BETWEEN 100-n AND 100+n
I want to create different intervalls:
0 to 10 steps 1
10 to 100 steps 10
100 to 1.000 steps 100
1.000 to 10.000 steps 1.000
to query a table for count the items.
with "series" as (
(SELECT generate_series(0, 10, 1) AS r_from)
union
(select generate_series(10, 90, 10) as r_from)
union
(select generate_series(100, 900, 100) as r_from)
union
(select generate_series(1000, 9000, 1000) as r_from)
order by r_from
)
, "range" as ( select r_from
, case
when r_from < 10 then r_from + 1
when r_from < 100 then r_from + 10
when r_from < 1000 then r_from + 100
else r_from + 1000
end as r_to
from series)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";
I think generate_series is the right way, there is another way, we can use simple math to calculate the numbers.
SELECT 0 as r_from,1 as r_to
UNION ALL
SELECT power(10, steps ) * v ,
power(10, steps ) * v + power(10, steps )
FROM generate_series(1, 9, 1) v
CROSS JOIN generate_series(0, 3, 1) steps
so that might as below
with "range" as
(
SELECT 0 as r_from,1 as r_to
UNION ALL
SELECT power(10, steps) * v ,
power(10, steps) * v + power(10, steps)
FROM generate_series(1, 9, 1) v
CROSS JOIN generate_series(0, 3, 1) steps
)
select r_from, r_to,(SELECT count(*) FROM "my_table" WHERE "my_value" BETWEEN r_from AND r_to) as "Anz."
FROM "range";
sqlifddle
Rather than generate_series you could create defined integer range types (int4range), then test whether your value is included within the range (see Range/Multirange Functions and Operators. So
with ranges (range_set) as
( values ( int4range(0,10,'[)') )
, ( int4range(10,100,'[)') )
, ( int4range(100,1000,'[)') )
, ( int4range(1000,10000,'[)') )
) --select * from ranges;
select lower(range_set) range_start
, upper(range_set) - 1 range_end
, count(my_value) cnt
from ranges r
left join my_table mt
on (mt.my_value <# r.range_set)
group by r.range_set
order by lower(r.range_set);
Note the 3rd parameter in creating the ranges.
Creating a CTE as above is good if your ranges are static, however if dynamic ranges are required you can put the ranges into a table. Changes ranges then becomes a matter to managing the table. Not simple but does not require code updates. The query then reduces to just the Main part of the above:
select lower(range_set) range_start
, upper(range_set) - 1 range_end
, count(my_value) cnt
from range_tab r
left join my_table mt
on (mt.my_value <# r.range_set)
group by r.range_set
order by lower(r.range_set);
See demo for both here.
Today I am attempting to use the COUNT(*) function to return rows that match my criteria as seen below.
SELECT COUNT(*)
FROM "mv_fundraiser_report"
WHERE thank_you_delivered = true
What I am attempting to do is to perform a different calculation based on the number that is returned. For instance:
If COUNT > 2000
RETURN COUNT * 2
If COUNT < 2000
RETURN COUNT * 3
I'm looking for guidance as to how I could execute this task within PostgreSQL. Thanks!
Using condition expression CASE
select case
when cnt > 2000
then cnt * 2
else cnt * 3
end new_cnt
from (
select COUNT(*) as cnt
from "mv_fundraiser_report"
where thank_you_delivered = true
) t
Is it possible to do this:
SELECT * FROM public."LamcApiCalls" WHERE generalstatuscode=0 AND sendondate < NOW() AND push = 1
UNION ALL
SELECT * FROM public."LamcApiCalls" WHERE generalstatuscode=0 AND sendondate < NOW() AND push IS NULL ORDER BY random() LIMIT 50
It's failing because of the ORDER BY and LIMIT on the second query. Is there anyway to do that?
Thanks
You can put the second query into a subquery:
SELECT * FROM public."LamcApiCalls" WHERE generalstatuscode=0 AND sendondate < NOW() AND push = 1
UNION ALL
SELECT
*
FROM (
SELECT * FROM public."LamcApiCalls" WHERE generalstatuscode=0 AND sendondate < NOW() AND push IS NULL ORDER BY random() LIMIT 50
) s
I have two tables q1data and q1lookup in postgres database. q1data contains 3 columns (postid, reasonid, other) and q1lookup contains 2 columns (reasonid, reason).
I am trying to create a view which will include 4 columns (reasonid, reason, count, percentage). count is the count of each reason and percentage should be each count divided by total of count(*) from q1data (i.e. total rows if reasonid).
But it gives an error and says syntax error near count(*). The following is the code I am using. Please help.
select
cwfis_web.q1data.reasonid AS reasonid,
cwfis_web.q1lookup.reason AS reason,
count(cwfis_web.q1data.reasonid) AS count,
round(
(
(
count(cwfis_web.q1data.reasonid)
/
(select count(0) AS count(*) from cwfis_web.q1data)
) * 100
)
,0) AS percentage
from
cwfis_web.q1data
join
cwfis_web.q1lookup
ON cwfis_web.q1data.reasonid = cwfis_web.q1lookup.reasonid
group by
cwfis_web.q1data.reasonid;
Firstly, you have a completely invalid piece of syntax there: count(0) AS count(*). Replacing that with a plain count(*), and adding the missing Group By entry for reason, gives this:
select
cwfis_web.q1data.reasonid AS reasonid,
cwfis_web.q1lookup.reason AS reason,
count(cwfis_web.q1data.reasonid) AS count,
round(
(
(
count(cwfis_web.q1data.reasonid)
/
(select count(*) from cwfis_web.q1data)
) * 100
)
,0) AS percentage
from
cwfis_web.q1data
join
cwfis_web.q1lookup
ON cwfis_web.q1data.reasonid = cwfis_web.q1lookup.reasonid
group by
cwfis_web.q1data.reasonid,
cwfis_web.q1lookup.reason;
However, as this live demo shows this doesn't give the right value for percentage, because count(cwfis_web.q1data.reasonid) and (select count(*) from cwfis_web.q1data) are both of type integer, so integer division is performed, and the result truncated to 0.
If you cast these to numeric (the expected argument type of the 2-parameter round() function, you get this:
select
cwfis_web.q1data.reasonid AS reasonid,
cwfis_web.q1lookup.reason AS reason,
count(cwfis_web.q1data.reasonid) AS count,
round(
(
(
count(cwfis_web.q1data.reasonid)::numeric
/
(select count(*) from cwfis_web.q1data)::numeric
) * 100
)
,0) AS percentage
from
cwfis_web.q1data
join
cwfis_web.q1lookup
ON cwfis_web.q1data.reasonid = cwfis_web.q1lookup.reasonid
group by
cwfis_web.q1data.reasonid,
cwfis_web.q1lookup.reason;
Which as this live demo shows gives something more like you were hoping for. (Alternatively, you can cast to float, and lose the ,0 argument to round(), as in this demo.)
Try changing your subquery from
select count(0) AS count(*) from cwfis_web.q1data
to
select count(0) from cwfis_web.q1data
Also you need to add cwfis_web.q1lookup.reason to group by.