Convert a nested subquery into normal query - sql

I have problem with following query where in which the nested query should be
converted to normal query:
select
count(*) as count,
TO_CHAR(RH.updated_datetime,'DD-MM-YYYY HH:MI:SS') as date,
SUM(
extract (
epoch from (
RH.updated_datetime - PRI.procedure_performed_datetime
)
)/60
)::integer/count(*) as diff
from
procedure_runtime_information PRI,
study S,
report R,
report_history RH
where
RH.report_fk = R.pk AND
R.study_fk = S.pk AND
S.procedure_runtime_fk = PRI.pk AND
RH.old_status_fk = 21 AND
RH.revision = (select max(revision) from report_history where RH.report_fk = RH.report_fk) AND
RH.updated_datetime > TO_DATE('22-01-2013 00:00:00', 'DD-MM-YYYY HH24:MI:SS') AND RH.updated_datetime < TO_DATE('22-01-2014 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
group by date order by date asc;

Assuming this
(select max(revision) from report_history where RH.report_fk = RH.report_fk)
should really be:
(select max(revision) from report_history x where x.report_fk = RH.report_fk)
You could transform the nested (correlated) subquery into a plain subquery like this (one way of many):
SELECT count(*) AS ct
,to_char(rh.updated_datetime,'DD-MM-YYYY HH:MI:SS') AS date -- HH24?
,sum(extract(epoch FROM (RH.updated_datetime
- PRI.procedure_performed_datetime))
/ 60)::int / count(*) AS diff
FROM procedure_runtime_information PRI
JOIN study S ON S.procedure_runtime_fk = PRI.pk
JOIN report R ON R.study_fk = S.pk
JOIN report_history RH ON RH.report_fk = R.pk
JOIN (
SELECT report_fk, max(revision) AS revision
FROM report_history RH1
GROUP BY 1
) RH1 ON RH1.report_fk = RH.report_fk
AND RH1.revision = RH.revision
WHERE RH.old_status_fk = 21
AND RH.updated_datetime > to_date('22-01-2013', 'DD-MM-YYYY') -- >= ?
AND RH.updated_datetime < to_date('22-01-2014', 'DD-MM-YYYY') -- to_timestamp?
GROUP BY date -- where does date come from?
ORDER BY date;

Related

Divide results from two query by another query in SQL

I have this query in Metabase:
with l1 as (SELECT date_trunc ('day', Ticket_Escalated_At) as time_scale, count (Ticket_ID) as chat_per_day
FROM CHAT_TICKETS where SUPPORT_QUEUE = 'transfer_investigations'
and date_trunc('month', TICKET_ESCALATED_AT) > now() - interval '6' Month
GROUP by 1)
with l2 as (SELECT date_trunc('day', created_date) as week, count(*) as TI_watchman_ticket
FROM jira_issues
WHERE issue_type NOT IN ('Transfer - General', 'TI - Advanced')
and date_trunc('month', created_date) > now() - interval '6' Month
and project_key = 'TI2'
GROUP BY 1)
SELECT l1.* from l1
UNION SELECT l2.* from l2
ORDER by 1
and this one:
with hours as (SELECT date_trunc('day', ws.start_time) as date_
,(ifnull(sum((case when ws.shift_position = 'TI - Non-watchman' then (minutes_between(ws.end_time, ws.start_time)/60) end)),0) + ifnull(sum((case when ws.shift_position = 'TI - Watchman' then (minutes_between(ws.end_time, ws.start_time)/60) end)),0) ) as total
from chat_agents a
join wiw_shifts ws on a.email = ws.user_email
left join people_ops.employees h on substr(h.email,1, instr(h.email,'#revolut') - 1) = a.login
where (seniority != 'Lead' or seniority is null)
and date_trunc('month', ws.start_time) > now() - interval '6' Month
GROUP BY 1)
I would like to divide the output of the UNION of the first one, by the result of the second one, any ideas.

Retrieve start and last created date from a duplicated record

I have a table called mov_entrys and they have multiple historic records, in other words, duplicated records this is my main SQL statement
SELECT me.mov_entry_id, me.mov_entry_ean13, me.plate, mv.name vehiclename,
ma.name areaname, ml.name locationame, me.value, mov_pay.name paytype ,me.validated, me_usu.name operatorName,
to_char(me.created_at, 'DD/MM/YYYY HH24:MI:SS') created_at,
to_char(me.updated_at, 'DD/MM/YYYY HH24:MI:SS') updated_at
FROM mov_entrys me
LEFT OUTER JOIN mov_payment_type mov_pay on mov_pay.mov_payment_type_id = me.mov_payment_type_id
JOIN mov_vehicles mv ON me.mov_vehicle_id = mv.mov_vehicle_id
JOIN mov_areas ma ON me.mov_area_id = ma.mov_area_id
JOIN mov_locations ml ON ma.mov_location_id = ml.mov_location_id
JOIN mov_users me_usu ON me.mov_user_id = me_usu.mov_user_id
WHERE me.value > 0
AND me.validated <> 'O'
AND me.validated <> 'V'
AND me.validated <> 'I'
AND me.created_at >= date_trunc('month', NOW()) - '1 month'::interval
order by mov_entry_id desc
But the records are like this example:
id ean13 value validated created_at updated_at
1 7800003378198 0 N 2019-10-04 09:00:31 2019-10-04 09:00:31
2 7800003378198 8 S 2019-10-04 13:01:11 2019-10-04 13:01:11
3 7800003378198 10.5 AD 2019-10-04 13:02:13 2019-10-04 13:02:13
3 7800003378198 10.5 I 2019-10-04 13:05:13 2019-10-04 13:05:13
In Laravel when a data is created the created_at and updated_at is the same data, but I want the start date and last date from this record that has the same ean13 data 7800003378198
The main query returns the record that I want but with the same data and I want the real created data and last data
if you think the record in the top, I want the return like this, if I use group I cant have like this
id ean13 value validated created_at updated_at
2 7800003378198 8 S 2019-10-04 09:00:31 2019-10-04 13:05:13
3 7800003378198 10.5 AD 2019-10-04 09:00:31 2019-10-04 13:05:13
I try to make a subquery but I don't know why always make an INFINITE load to return a data I think I'm doing something wrong, this is my query with subquery
SELECT me.mov_entry_id, me.mov_entry_ean13, me.plate, mv.name vehiclename,
ma.name areaname, ml.name locationame, me.value, mov_pay.name paytype ,me.validated, me_usu.name operatorName,
to_char(me.created_at, 'DD/MM/YYYY HH24:MI:SS') created_at,
to_char(me.updated_at, 'DD/MM/YYYY HH24:MI:SS') updated_at,
(
SELECT me_v2.created_at FROM mov_entrys me_v2 WHERE me.mov_entry_ean13 = me_v2.mov_entry_ean13
ORDER BY me_v2.created_at DESC
LIMIT 1
) date_test
FROM mov_entrys me
LEFT OUTER JOIN mov_payment_type mov_pay on mov_pay.mov_payment_type_id = me.mov_payment_type_id
JOIN mov_vehicles mv ON me.mov_vehicle_id = mv.mov_vehicle_id
JOIN mov_areas ma ON me.mov_area_id = ma.mov_area_id
JOIN mov_locations ml ON ma.mov_location_id = ml.mov_location_id
JOIN mov_users me_usu ON me.mov_user_id = me_usu.mov_user_id
WHERE me.value > 0
AND me.validated <> 'O'
AND me.validated <> 'V'
AND me.validated <> 'I'
AND me.created_at >= date_trunc('month', NOW()) - '1 month'::interval
order by mov_entry_id desc
When I execute this query alone it is working fine giving me the last record,
what I'm doing wrong? This is my test query :
SELECT me.created_at FROM mov_entrys me WHERE me.mov_entry_ean13 = '7800003378198'
ORDER BY me.created_at DESC
LIMIT 1
I mana
Consider aggregating on dates with MIN and MAX, grouping by all other SELECT columns. Below uses shorter aliases for readability:
SELECT e.mov_entry_id, e.mov_entry_ean13, e.plate, v.name AS vehiclename,
a.name AS areaname, l.name AS locationame, e.value, p.name AS paytype,
e.validated, u.name AS operatorName,
to_char(MIN(e.created_at), 'DD/MM/YYYY HH24:MI:SS') AS created_at,
to_char(MAX(e.updated_at), 'DD/MM/YYYY HH24:MI:SS') AS updated_at
FROM mov_entrys e
LEFT OUTER JOIN mov_payment_type p ON p.mov_payment_type_id = e.mov_payment_type_id
INNER JOIN mov_vehicles v ON e.mov_vehicle_id = v.mov_vehicle_id
INNER JOIN mov_areas a ON e.mov_area_id = a.mov_area_id
INNER JOIN mov_locations l ON a.mov_location_id = l.mov_location_id
INNER JOIN mov_users u ON e.mov_user_id = u.mov_user_id
WHERE e.value > 0
AND e.validated <> 'O'
AND e.validated <> 'V'
AND e.validated <> 'I'
AND e.created_at >= date_trunc('month', NOW()) - '1 month'::interval
GROUP BY e.mov_entry_id, e.mov_entry_ean13, e.plate, v.name,
a.name,l.name, e.value, p.name, e.validated, u.name
ORDER BY e.mov_entry_id desc

Find increase in history records in specific range

I want to find records in date range 1/1/19-1/7/19 which increase amount
using table HISTORY:
DATE AMOUNT ID
(Date, number, varchar2(30))
I find IDs inside range correctly
assuming increase/decrease can happens only when having two records with same Id
with suspect as
(select id
from history
where t.createddate < to_date('2019-07-01', 'yyyy-mm-dd')
group by id
having count(1) > 1),
ids as
(select id
from history
join suspect
on history.id = suspect.id
where history.date > to_date('2019-01-01', 'yyyy-mm-dd')
and history.date < to_date('2019-07-01', 'yyyy-mm-dd'))
select count(distinct id)
from history a, history b
where a.id = b.id
and a.date < b.date
and a.amount < b.amount
The problem to find increase I need to find previous record which can be before time range
I can find last previous time before time range, but I failed to use it:
ids_prevtime as (
select history.*, max(t.date) over (partition by t.id) max_date
from history
join ids on history.userid = ids.id
where history.date < to_date('2019-01-01','yyyy-mm-dd' )
), ids_prev as (
select * from ids_prevtime where createdate=max_date
)
I see that you found solution, but maybe you could do it simpler, using lag():
select count(distinct id)
from (select id, date_, amount,
lag(amount) over (partition by id order by date_) prev_amt
from history)
where date_ between date '2019-01-01' and date '2019-07-01'
and amount > prev_amt;
dbfiddle
Add union of last history records before range with records inside range
ids_prev as
(select ID, DATE, AMOUNT
from id_before_rangetime
where createddate = max_date),
ids_in_range as
(select history.*
from history
join ids
on history.ID = ids.ID
where history.date > to_date('2019-01-01', 'yyyy-mm-dd')
and history.date < to_date('2019-07-01', 'yyyy-mm-dd')),
all_relevant as
(select * from ids_in_range union all select * from ids_prev)
and then count increases:
select count(distinct id)
from all_relevant a, all_relevant b
where a.id = b.id
and a.date < b.date
and a.amount < b.amount

Postgres sub query returns 1 row, but exists returns false

I'm not sure how this is possible. This is an inner query for a NOT EXISTS test.
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
;
(1 row)
If I change the outer SELECT to count(subq.*) I get:
count
1
So far so good. But wrap the entire original query in SELECT EXISTS and:
exists
f
Why is this? I need this query to be wrapped in an outer query:
SELECT * FROM "clients" AS c WHERE status = 'Active' AND NOT EXISTS(
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = c.id
);
It is returning a row for the outer query even though the inner query returns 1 row.
Edit to add SELECT EXISTS:
SELECT EXISTS(
SELECT subq.* FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
);
exists
f
(1 row)
And just for completeness:
SELECT 1 FROM(
SELECT distinct on("contractId") "contractId", clients.id, clients.name, "contractHistory".status, "contractHistory"."timeStamp", first_value("contractHistory"."id") over(partition by "contractId" order by "timeStamp" desc) as window
FROM "contractHistory", "clients", "contracts"
WHERE "contractHistory"."contractId" = "contracts"."id"
AND "clients"."id" = "contracts"."clientId"
AND contracts.opened < now()
AND contracts.expires > now() + '1 day'::interval
) AS subq
WHERE subq.status = 'Signed'
AND subq.id = 12345
?column?
(0 rows)

Oracle SQL Correlated Subquery (in WHERE statement) having no results

Hi and thanks for reading,
I am trying to run the following SQL query with correlated subquery and it is bringing back no results. I am using the subquery to only bring back results that have the lowest date range. Both the query alone and the subquery alone work fine.
Any ideas? Am I linking the correlated subquery incorrectly?
Note: The correlated subquery is on the last line of the query
Thank you,
Willz06jw
SELECT aaa."effective_time",
aaa."event_type_c",
"clarity_dep"."department_name",
"patient"."birth_date",
"patient"."pat_mrn_id",
"zc_ped_delivr_meth"."name",
"zc_ped_delivr_meth"."ped_delivr_meth_c",
aaa."department_id",
"clarity_dep"."department_id",
aaa."alt_event_type_c",
aaa."in_event_type_c"
FROM (("CLARITY"."clarity_adt" aaa
inner join "CLARITY"."clarity_dep" "CLARITY_DEP"
ON aaa."department_id" = "clarity_dep"."department_id")
inner join "CLARITY"."patient" "PATIENT"
ON aaa."pat_id" = "patient"."pat_id")
inner join "CLARITY"."zc_ped_delivr_meth" "ZC_PED_DELIVR_METH"
ON "patient"."ped_delivr_meth_c" =
"zc_ped_delivr_meth"."ped_delivr_meth_c"
WHERE ( "patient"."birth_date" >= To_date ('01-12-2012 00:00:00',
'DD-MM-YYYY HH24:MI:SS')
AND "patient"."birth_date" < To_date ('06-12-2012 00:00:00',
'DD-MM-YYYY HH24:MI:SS'
) )
AND ( aaa."department_id" = 236601
OR aaa."department_id" = 236703
OR aaa."department_id" = 236801
OR aaa."department_id" = 236901
OR aaa."department_id" = 237101
OR aaa."department_id" = 237201 )
AND aaa."event_type_c" = 3
AND aaa."effective_time" = (SELECT Min(bbb."effective_time")
FROM "clarity_adt" bbb
WHERE aaa."pat_id" = bbb.pat_id)
Without zifting through the entire statement, the easiest solution would be to just wrap the statement in a select using the ROW_NUMBER function to get the lowest dates.
SQL Statement 1
SELECT *
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY pat_id ORDER BY effective_time) AS rn,
aaa."effective_time",
aaa."event_type_c",
"clarity_dep"."department_name",
"patient"."birth_date",
"patient"."pat_mrn_id",
"zc_ped_delivr_meth"."name",
"zc_ped_delivr_meth"."ped_delivr_meth_c",
aaa."department_id",
"clarity_dep"."department_id",
aaa."alt_event_type_c",
aaa."in_event_type_c"
FROM "CLARITY"."clarity_adt" aaa
inner join "CLARITY"."clarity_dep" "CLARITY_DEP" ON aaa."department_id" = "clarity_dep"."department_id"
inner join "CLARITY"."patient" "PATIENT" ON aaa."pat_id" = "patient"."pat_id"
inner join "CLARITY"."zc_ped_delivr_meth" "ZC_PED_DELIVR_METH" ON "patient"."ped_delivr_meth_c" = "zc_ped_delivr_meth"."ped_delivr_meth_c"
WHERE ( "patient"."birth_date" >= To_date ('01-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
AND "patient"."birth_date" < To_date ('06-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS' ) )
AND ( aaa."department_id" = 236601 OR aaa."department_id" = 236703 OR aaa."department_id" = 236801 OR aaa."department_id" = 236901 OR aaa."department_id" = 237101 OR aaa."department_id" = 237201 )
AND aaa."event_type_c" = 3
) q
WHERE q.rn = 1
Your statement could be simplified (in reading it) by using an IN statement io. all the ORstatements like such
SQL Statement 2
SELECT *
FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY pat_id ORDER BY effective_time) AS rn,
aaa."effective_time",
aaa."event_type_c",
"clarity_dep"."department_name",
"patient"."birth_date",
"patient"."pat_mrn_id",
"zc_ped_delivr_meth"."name",
"zc_ped_delivr_meth"."ped_delivr_meth_c",
aaa."department_id",
"clarity_dep"."department_id",
aaa."alt_event_type_c",
aaa."in_event_type_c"
FROM "CLARITY"."clarity_adt" aaa
inner join "CLARITY"."clarity_dep" "CLARITY_DEP" ON aaa."department_id" = "clarity_dep"."department_id"
inner join "CLARITY"."patient" "PATIENT" ON aaa."pat_id" = "patient"."pat_id"
inner join "CLARITY"."zc_ped_delivr_meth" "ZC_PED_DELIVR_METH" ON "patient"."ped_delivr_meth_c" = "zc_ped_delivr_meth"."ped_delivr_meth_c"
WHERE ( "patient"."birth_date" >= To_date ('01-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
AND "patient"."birth_date" < To_date ('06-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS' ) )
AND ( aaa."department_id" IN (236601,236703,236801,236901,237101,237201) )
AND aaa."event_type_c" = 3
) q
WHERE q.rn = 1
In the end, I would even simplify it further by aliassing all tables and use a WITH statement. The final result would look like this
SQL Statement 3
;WITH q AS (
SELECT ROW_NUMBER() OVER (PARTITION BY pat_id ORDER BY effective_time) AS rn,
aaa."effective_time",
aaa."event_type_c",
cd."department_name",
p."birth_date",
p."pat_mrn_id",
pdm."name",
pdm."ped_delivr_meth_c",
aaa."department_id",
cd."department_id",
aaa."alt_event_type_c",
aaa."in_event_type_c"
FROM "CLARITY"."clarity_adt" aaa
inner join "CLARITY"."clarity_dep" cd ON aaa."department_id" = cd."department_id"
inner join "CLARITY"."patient" p ON aaa."pat_id" = p."pat_id"
inner join "CLARITY"."zc_ped_delivr_meth" pdm ON p."ped_delivr_meth_c" = pdm."ped_delivr_meth_c"
WHERE p."birth_date" >= To_date ('01-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS'
AND p."birth_date" < To_date ('06-12-2012 00:00:00', 'DD-MM-YYYY HH24:MI:SS' ) )
AND aaa."department_id" IN (236601,236703,236801,236901,237101,237201)
AND aaa."event_type_c" = 3
)
SELECT *
FROM q
WHERE rn = 1
You're only going to get rows if the row with the earliest date also matches the other conditions on clarity_adt. If you want the earliest record for that subset then you'd have to push those conditions into the subquery.