append subquery based on case- postgresql - postgresql

My table is crash
id
jurisdiction
drugs_inv
alcohol_inv
dr_sex
severity_id
1
NT
true
false
Male
3
2
NSW
false
false
Male
3
3
WA
true
true
Female
3
4
WA
true
true
Male
4
I want to have a subquery based on t_factors array
if it has 1 then filter where alcohol_inv = true
if it has 2 then filter where drugs_inv = true
if both 1 and 2 then use both above conditions
something like may be append a subquery...within the query in the following spaces..
[subqry for alcohol_inv = true]
[subqry for drugs_inv = true]
how to go about it?
My query:
WITH myvars(t_state,
t_factors,
) AS(values(
'WA',
'{1,2}', --factors
))
SELECT
dr_sex,
COUNT(*) as all_crashes,
COUNT(t1.id) filter (WHERE severity_id >= 3) as fsi_crashes,
COUNT(t1.id) filter (WHERE severity_id = 3) as si_crashes,
COUNT(t1.id) filter (WHERE severity_id = 4) as fatal_crashes
FROM
crash t1
,myvars
WHERE
(jurisdiction = t_state OR t_state is null)
AND (( CASE
WHEN 1 = ANY (t_factors) THEN '[subqry for alcohol_inv = true]'
WHEN 2 = ANY (t_factors) THEN '[subqry for drugs_inv = true]'
END) factor
OR
t_factors is null)
AND severity_id > 1
AND dr_sex = ANY( '{Male, Female}'::text[] )
GROUP BY dr_sex

Since alcohol_inv is boolean then [subqry for alcohol_inv = true] is simply alcohol_inv. Maybe this query will do the job then
WITH myvars(t_state, t_factors) AS
(
values ('WA', '{1,2}'::integer[])
)
SELECT
dr_sex,
COUNT(*) as all_crashes,
COUNT(t1.id) filter (WHERE severity_id >= 3) as fsi_crashes,
COUNT(t1.id) filter (WHERE severity_id = 3) as si_crashes,
COUNT(t1.id) filter (WHERE severity_id = 4) as fatal_crashes
FROM
crash t1, myvars
WHERE
(jurisdiction = t_state OR t_state is null)
AND
(
CASE WHEN 1 = ANY(t_factors) THEN alcohol_inv
WHEN 2 = ANY(t_factors) THEN drugs_inv END
OR t_factors is null
)
AND severity_id > 1
AND dr_sex in ('Male', 'Female')
GROUP BY dr_sex;

Related

Return in just one lines

I have a problem, I have a query in postgresql and I need to do a SUM, however, it returns me a total of 4 lines because the ids of my routes are different, and I need to add the "totalChecklists" and return the amount of all in one line.
select "users"."id",
count((cycles.adherence >= 100 and cycles.justified = false) or null) as "routesDone",
count((cycles.adherence < 100 and cycles.opened = false) or null) as "routesNotDone",
count((cycles.opened = true and cycles.adherence < 100) or null) as "routesOpened",
count(cycles.justified or null) as "routesJustified",
routes."totalSpots" AS "totalCheck",
count(cycles.id) as "routesOnPeriod",
(
count((cycles.adherence >= 100 and cycles.justified = false) or null) +
count((cycles.adherence < 100 and cycles.opened = false) or null) +
count((cycles.opened = true and cycles.adherence < 100) or null) +
count(cycles.justified or null)
) as "routesTotal",
0 as "routesDoneLate",
0 as "routesLate",
SUM(case when cycles.adherence >= 100 then routes."totalAssets" else 0 end) AS "coveredAssets",
SUM(case when cycles.adherence < 100 then routes."totalAssets" else 0 end) AS "uncoveredAssets"
from "routes"
inner join "cycles" on "routes"."identifier" = "cycles"."routeIdentifier"
inner join "workspaces" on "cycles"."workspaceId" = "workspaces"."id"
inner join "users" on "users"."id" = "cycles"."inspectorId"
where "routes"."deleted_at" is null
and "cycles"."deletedAt" is null
and "workspaces"."deleted" = false
and "cycleStartAt" <= '2022-07-11T02:59:59Z'
and "cycleEndAt" >= '2022-04-12T03:00:00Z'
and "users"."id" = 'b67830a7-39fc-4ad5-bf26-07a43dcd3676'
and "routes"."contextPath" like '/malicious-interaction-murder-32%'
and "routes"."deleted_at" is null
group by
users.id,
routes.id
My return:
Sorry for my bad english, I hope I managed to be very clear.
Thank you very much in advance

Combining Two Queries and Calculating Result

I am attempting to calculate the difference between query 1:
select case
when cnt >= 1 AND cnt <= 2000 then cnt * 6
when cnt >= 2001 AND cnt <= 4000 then ((cnt - 2000) * 5) + 12000
when cnt >= 4001 AND cnt <= 6000 then ((cnt - 4000) * 4) + 22000
when cnt >= 6001 AND cnt <= 8000 then ((cnt - 6000) * 3) + 30000
when cnt >= 8001 then ((cnt - 8000) * 2) + 36000
else 1
end "Customer Investment"
from (
select COUNT(*) as cnt
from "mv_fundraiser_report"
where thank_you_delivered = true
[[AND {{NonProfit}}]]
[[AND {{StartDate}}]]
) t
And Query 2:
SELECT ((cast(A.TNUM as float)/cast(A.TDENOM as float))-(cast(A.FNUM as float)/cast(A.FDENOM as float)))*cast(A.TDENOM as float) AS "Heck"
FROM (SELECT
(SELECT SUM("public"."mv_fundraiser_report"."total_raised")
FROM "public"."mv_fundraiser_report"
WHERE ("public"."mv_fundraiser_report"."opt-in" = FALSE
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 704943916598630
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 193572775319413
AND NOT(first_name IS NULL
AND total_raised > 1000
AND fundraiser_type = 'Generic Fundraiser')
AND [[{{NonProfit}}]]
AND [[{{DateRange}}]])) AS FNUM,
(SELECT count(*) AS "count"
FROM "public"."mv_fundraiser_report"
WHERE ("public"."mv_fundraiser_report"."opt-in" = FALSE
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 704943916598630
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 193572775319413
AND NOT(first_name IS NULL
AND total_raised > 1000
AND fundraiser_type = 'Generic Fundraiser')
AND [[{{NonProfit}}]]
AND [[{{DateRange}}]])) AS FDENOM,
(SELECT SUM("public"."mv_fundraiser_report"."total_raised")
FROM "public"."mv_fundraiser_report"
WHERE ("public"."mv_fundraiser_report"."opt-in" = TRUE
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 704943916598630
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 193572775319413
AND NOT(first_name IS NULL
AND total_raised > 1000
AND fundraiser_type = 'Generic Fundraiser')
AND [[{{NonProfit}}]]
AND [[{{DateRange}}]])) AS TNUM,
(SELECT count(*) AS "count"
FROM "public"."mv_fundraiser_report"
WHERE ("public"."mv_fundraiser_report"."opt-in" = TRUE
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 704943916598630
AND NOT "public"."mv_fundraiser_report"."campaign_id" = 193572775319413
AND NOT(first_name IS NULL
AND total_raised > 1000
AND fundraiser_type = 'Generic Fundraiser')
AND [[{{NonProfit}}]]
AND [[{{DateRange}}]])) AS TDENOM) A
Both of the queries work by themselves and return a single number, but I am struggling heavily with the syntax. I'm totally unsure of how I can make use of (window?) functions in order to achieve my end result. Any help is appreciated, thanks!
You can place each query into common table expressions, then subtract one from the other.
For example (reworked query 2 for simplification):
WITH one AS (
SELECT
CASE
WHEN cnt >= 1 AND cnt <= 2000 THEN cnt * 6
WHEN cnt >= 2001 AND cnt <= 4000 THEN ((cnt - 2000) * 5) + 12000
WHEN cnt >= 4001 AND cnt <= 6000 THEN ((cnt - 4000) * 4) + 22000
WHEN cnt >= 6001 AND cnt <= 8000 THEN ((cnt - 6000) * 3) + 30000
WHEN cnt >= 8001 THEN ((cnt - 8000) * 2) + 36000
ELSE 1
END "Customer Investment"
FROM (
SELECT COUNT(*) as cnt
FROM "mv_fundraiser_report"
WHERE thank_you_delivered = true
[[AND {{NonProfit}}]]
[[AND {{StartDate}}]]
) t
),
two AS (
SELECT (
(
SUM(public.mv_fundraiser_report.total_raised)
FILTER (WHERE public.mv_fundraiser_report.opt-in = FALSE)
)::float AS FNUM /
(
count(*)
FILTER (WHERE public.mv_fundraiser_report.opt-in = FALSE)
)::float AS FDENOM
) -
(
(
SUM(public.mv_fundraiser_report.total_raised)
FILTER (WHERE public.mv_fundraiser_report.opt-in = TRUE)
)::float AS TNUM /
(
count(*)
FILTER (WHERE public.mv_fundraiser_report.opt-in = TRUE)
)::float AS TDENOM
) AS "Heck"
FROM public.mv_fundraiser_report
WHERE NOT public.mv_fundraiser_report.campaign_id = 704943916598630
AND NOT public.mv_fundraiser_report.campaign_id = 193572775319413
AND NOT (first_name IS NULL
AND total_raised > 1000
AND fundraiser_type = 'Generic Fundraiser')
AND [[{{NonProfit}}]]
AND [[{{DateRange}}]])
)
SELECT one."Customer Investment" - two."Heck" AS difference
FROM one, two;
I don't have your data or schema to test this against, so this untested.

Sum two columns values in same table on postgresql query

SELECT c.period,
c.idsr_incident_id_id,
c.idsr_disease_id_id,
CASE WHEN idsr_incident_id_id = 1 OR idsr_incident_id_id = 3 THEN SUM(c.data_value::integer) ELSE 0 END AS cases,
CASE WHEN idsr_incident_id_id = 2 OR idsr_incident_id_id = 4 THEN SUM(c.data_value::integer) ELSE 0 END AS deaths
FROM veoc_idsr_weekly_national_report c
LEFT JOIN veoc_idsr_diseases b ON b.id = c.idsr_disease_id_id
LEFT JOIN veoc_idsr_reported_incidents j ON j.id = c.idsr_incident_id_id
WHERE c.idsr_incident_id_id >= 1 AND c.idsr_incident_id_id <= 4 AND idsr_disease_id_id = 10 AND period ='2019W30'
GROUP BY c.period, c.idsr_incident_id_id, c.idsr_disease_id_id, c.data_value;`enter code here`
Below my query results:
I want to sum the cases and the death value columns since the period and disease_id is the same. I think my problem is on the Group By section but I cant solve it. If it means i must remove the incident_id column to get the totals it will still be fine.
Please, try with below query where sum of function place replaced:
SELECT c.period,
c.idsr_disease_id_id,
SUM(CASE WHEN idsr_incident_id_id = 1 OR idsr_incident_id_id = 3 THEN (c.data_value::integer) ELSE 0 END) AS cases,
SUM(CASE WHEN idsr_incident_id_id = 2 OR idsr_incident_id_id = 4 THEN (c.data_value::integer) ELSE 0 END) AS deaths
FROM veoc_idsr_weekly_national_report c
LEFT JOIN veoc_idsr_diseases b ON b.id = c.idsr_disease_id_id
LEFT JOIN veoc_idsr_reported_incidents j ON j.id = c.idsr_incident_id_id
WHERE c.idsr_incident_id_id >= 1 AND c.idsr_incident_id_id <= 4 AND idsr_disease_id_id = 10 AND period ='2019W30'
GROUP BY c.period, c.idsr_disease_id_id;

T-SQL Two counts with different where clause

I want to count values on a table with different where clauses and wondering if there is a better way of doing it.
In this code i count one value.
SELECT v.name, count(v.value) AS v1
FROM dbo.table as v
WHERE v.organisationID = 2
AND v.datecreated > '2018-01-01'
AND v.datecreated < '2018-05-01'
AND v.value = 1
GROUP BY v.name
I also want to count all rows with value = 2
my way of doing it is like this with a sub select.
SELECT v.name, count(v.value) AS v1, (SELECT v2.name, count(v2.value)
FROM dbo.table as v2
WHERE v2.organisationID = 2
AND v2.datecreated > '2018-01-01'
AND v2.datecreated < '2018-05-01'
AND v2.value = 2
GROUP BY v2.name) AS v2
FROM dbo.table as v
WHERE v.organisationID = 2
AND v.datecreated > '2018-01-01'
AND v.datecreated < '2018-05-01'
AND v.value = 1
GROUP BY v.name
The table contains > 100 millions rows so I really want the fastest way. I use clustered columnstore index on the table.
Is there some way of doing it whitout sub-select.
Pseudo code:
SELECT v.name, count(v.value where v.value=1) AS v1, count(v.value where v.value=2) AS v2
FROM dbo.table as v
WHERE v.organisationID = 2
AND v.datecreated > '2018-01-01'
AND v.datecreated < '2018-05-01'
GROUP BY v.name
Yes, just use a CASE expression:
SELECT v.name,
SUM(CASE WHEN v.value = 1 THEN 1 ELSE 0 END) AS v1,
SUM(CASE WHEN v.value = 2 THEN 1 ELSE 0 END) AS v2
FROM dbo.table as v
WHERE v.organisationID = 2
AND v.datecreated > '2018-01-01'
AND v.datecreated < '2018-05-01'
AND v.value IN (1,2)
GROUP BY v.name
;

PG: How to show total count for this query if result is 0

I have a postgres 9.6 table called selected_media, with a column called _type that is set to either book or movie.
I want to select the COUNT of each type, in 1 single row, like this:
25 | 715
To do this, I have this query:
SELECT
COALESCE(SUM(CASE WHEN _type = 'book' THEN 1 ELSE 0 END), 0) AS books_count,
COALESCE(SUM(CASE WHEN _type = 'movie' THEN 1 ELSE 0 END), 0) AS movies_count
FROM selected_media
WHERE subscriber_id = $1
The problem is 2 fold:
I want each column to show the respective total count for that _type only if the sum in that column happens to be 0 (none selected). This is because the UI/UX states "selecting 0 books or movies is the same as selecting all of them".
It needs to be fast, this table will have millions of rows in it
You can use COUNT with FILTER clause:
SELECT
COUNT(*) FILTER (WHERE _type = 'book') AS books_count,
COUNT(*) FILTER (WHERE _type = 'movie') AS movies_count
FROM selected_media
WHERE subscriber_id = $1;
More info here.
EDIT
Use a nested subquery to achieve your first need:
SELECT
CASE books_count WHEN 0 THEN (SELECT COUNT(*) FROM selected_media WHERE _TYPE = 'book') ELSE books_count END AS books_count_final,
CASE movies_count WHEN 0 THEN (SELECT COUNT(*) FROM selected_media WHERE _TYPE = 'movie') ELSE movies_count END AS movies_count_final
FROM
(
SELECT
COUNT(*) FILTER (WHERE _type = 'book') AS books_count,
COUNT(*) FILTER (WHERE _type = 'movie') AS movies_count
FROM
selected_media
WHERE
subscriber_id = $1
) AS sub_query
Or using a CTE:
WITH selected_media_sub AS (
SELECT
COUNT(*) FILTER (WHERE _type = 'book') AS books_count,
COUNT(*) FILTER (WHERE _type = 'movie') AS movies_count
FROM
selected_media
WHERE
subscriber_id = $1
)
SELECT
CASE books_count WHEN 0 THEN (SELECT COUNT(*) FROM selected_media WHERE _TYPE = 'book') ELSE books_count END AS books_count_final,
CASE movies_count WHEN 0 THEN (SELECT COUNT(*) FROM selected_media WHERE _TYPE = 'movie') ELSE movies_count END AS movies_count_final
FROM selected_media_sub;
BTW, if you need just a non-zero count you can do the following:
SELECT
COALESCE(NULLIF(COUNT(*) FILTER (WHERE _type = 'book'), 0), 1) AS books_count,
COALESCE(NULLIF(COUNT(*) FILTER (WHERE _type = 'movie'), 0), 1) AS movies_count
FROM
selected_media
WHERE
subscriber_id = $1