Converting Subquery into Single Query - sql

I've a query that has multiple subqueries with parameters as follows:
SELECT
V.EMPNO,
V.FIRST_NAME || ' ' || V.MIDDLE_NAME
|| ' '
|| V.LAST_NAME FULLNAME,
M.APP_NO,
K.TOTAL_AMT,
K.TOTAL_AMT - (SELECT
SUM(Q.RECAMOUNT)
FROM
LOAN_ADJ_DETAILS_NEW q
WHERE
Q.APP_NO = M.APP_NO
AND Q.RECDATE <= '01-AUG-2022') REMAINING,
(SELECT
SUM(P.RECAMOUNT)
FROM
LOAN_ADJ_DETAILS_NEW p
WHERE
P.APP_NO = M.APP_NO
AND P.RECDATE <= '01-AUG-2022') TOTALADJ,
(SELECT
COUNT(*)
FROM
LOAN_ADJ_DETAILS_NEW p
WHERE
P.APP_NO = M.APP_NO
AND P.RECDATE IS NOT NULL
AND P.RECDATE <= '01-AUG-2022') INSTALLMENT,
(SELECT
MAX(Q.RECAMOUNT)
FROM
LOAN_ADJ_DETAILS_NEW q
WHERE
Q.APP_NO = M.APP_NO
AND Q.RECDATE = '01-AUG-2022') LASTINSTALL,
(SELECT
MAX(S.RECDATE)
FROM
LOAN_ADJ_DETAILS_NEW s
WHERE
S.APP_NO = M.APP_NO
AND S.RECDATE <= '01-AUG-2022') LASTDATE,
(SELECT
SUM(P.RECAMOUNT)
FROM
LOAN_ADJ_DETAILS_NEW p
WHERE
P.APP_NO = M.APP_NO
AND P.RECDATE <= '01-AUG-2022') PAID
FROM
LOAN_ADJ_DETAILS_NEW m,
TBL_LOAN_MASTER k,
EMP_PERSONAL v
WHERE
V.EMPNO = M.EMPNO
AND K.LOAN_ID = M.APP_NO
AND M.RECAMOUNT > 0
AND M.RECDATE IS NOT NULL
AND M.RECDATE = '01-AUG-2022'
AND M.RECDATE >= '01-AUG-2022';
The query is simple, just to get user wise loan information. Now the thing is, I require to make it into one query something as follows:
SELECT * FROM TABLE WHERE COLUMN <= PARAMTER;
The above query will be used as a dynamic query from database to front-end. I was hoping if this could be converted to a single query or view anyway.

You can use analytic functions and combine the sub-queries into a single one in the FROM clause:
SELECT V.EMPNO,
V.FIRST_NAME || ' ' || V.MIDDLE_NAME || ' ' || V.LAST_NAME
AS FULLNAME,
M.APP_NO,
K.TOTAL_AMT,
K.TOTAL_AMT - m.paid AS REMAINING,
m.totaladj,
m.paid,
m.installment,
m.lastinstall,
m.lastdate
FROM ( SELECT app_no,
empno,
recamount,
recdate,
SUM(RECAMOUNT) OVER (PARTITION BY app_no) AS totaladj,
SUM(RECAMOUNT) OVER (PARTITION BY app_no) AS paid,
COUNT(*) OVER (PARTITION BY app_no) AS installment,
MAX(RECAMOUNT) OVER (PARTITION BY app_no) AS lastinstall,
MAX(RECDATE) OVER (PARTITION BY app_no) AS lastdate
FROM LOAN_ADJ_DETAILS_NEW
WHERE RECDATE <= DATE '2022-08-01'
) m
INNER JOIN TBL_LOAN_MASTER k
ON (K.LOAN_ID = M.APP_NO)
INNER JOIN EMP_PERSONAL v
ON (V.EMPNO = M.EMPNO)
WHERE M.RECAMOUNT > 0
AND M.RECDATE = DATE '2022-08-01';

Related

The query I ran returns 2 of the same column which isn't allowed in tableau and I can't fix the query

I need to be able to get rid of one of the workdate and one of the sr_name columns but I can't figure out how to.
I'm getting the query returned like this:
Query
I'm also getting this error message when entered into tableau:
The column 'sr_name' was specified multiple times for 'Custom SQL Query'.
Below is the code I have. If I remove a sr_name from either subquery there will be an error in the join clause.
select *
from
(
select s.sr_name, cast(punchdatetime as date) as workdate,
((datediff(second, min(case when p.InOut = 1 then punchdatetime end),
max(case when p.InOut = 0 then punchdatetime end))/3600) - .5) as
hoursworked
from PunchClock p join ServiceReps s on p.ServRepID = s.ServRepID
where punchyear >= 2019
group by s.sr_name, cast(punchdatetime as date)
) v
join
(
select sr_name, t.*,
calls = (select count(*) from CRM_Correspondence cr where
cast(cr.DateCreated as date) = workdate and StatusType like '%call%' and
cr.ServRepID = t.servrepid),
reaches = (select count(*) from CRM_Correspondence cr where
cast(cr.DateCreated as date) = workdate and (StatusType = 'call reached'
or StatusType like '%SCHEDULE%') and cr.ServRepID = t.servrepid),
books = (select count(*) from os_appointments o where cast(o.DateCreated
as date) = workdate and isnull(o.confirmedby, o.booked_by) =
t.servrepid),
attends = (select count(*) from os_appointments o where
cast(o.DateCreated as date) = workdate and isnull(o.confirmedby,
o.booked_by) = t.servrepid and o.appointmentStatus = 'attended')
from
(
select cast(cor.datecreated as date) workdate, cor.ServRepID
from CRM_Correspondence cor
where cor.datecreated > '2019-01-01'
group by cast(cor.datecreated as date), cor.servrepid
) t
join ServiceReps sr on t.ServRepID = sr.ServRepID
) u on v.sr_name = u.sr_name and v.workdate = u.workdate
I need the same results just without the duplicate column so I can enter the query into tableau.
This is challenging because you have so many subqueries here. This could be refactored to use a single query which is what I would do. But using the existing query you could do something along these lines.
I had to format this very differently so I could isolate each piece.
select v.sr_name
, v.workdate
, v.hoursworked
, u.ServRepID
, u.calls
, u.reaches
, u.books
, u.attends
from
(
select s.sr_name
, cast(punchdatetime as date) as workdate
, ((datediff(second, min(case when p.InOut = 1 then punchdatetime end), max(case when p.InOut = 0 then punchdatetime end))/3600) - .5) as hoursworked
from PunchClock p
join ServiceReps s on p.ServRepID = s.ServRepID
where punchyear >= 2019
group by s.sr_name
, cast(punchdatetime as date)
) v
join
(
select sr_name
, t.*
, calls =
(
select count(*)
from CRM_Correspondence cr
where cast(cr.DateCreated as date) = workdate
and StatusType like '%call%'
and cr.ServRepID = t.servrepid
)
, reaches =
(
select count(*)
from CRM_Correspondence cr
where cast(cr.DateCreated as date) = workdate
and (StatusType = 'call reached' or StatusType like '%SCHEDULE%')
and cr.ServRepID = t.servrepid
)
, books =
(
select count(*)
from os_appointments o
where cast(o.DateCreated as date) = workdate and isnull(o.confirmedby, o.booked_by) = t.servrepid
)
, attends =
(
select count(*)
from os_appointments o
where cast(o.DateCreated as date) = workdate
and isnull(o.confirmedby, o.booked_by) = t.servrepid
and o.appointmentStatus = 'attended'
)
from
(
select cast(cor.datecreated as date) workdate
, cor.ServRepID
from CRM_Correspondence cor
where cor.datecreated > '2019-01-01'
group by cast(cor.datecreated as date)
, cor.servrepid
) t
join ServiceReps sr on t.ServRepID = sr.ServRepID
) u on v.sr_name = u.sr_name
and v.workdate = u.workdate

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)

Row-wise count group by variables

I have the below query -
SELECT
P.PRODUCT_NUMBER,
P.PRODUCT_DESCRIPTION,
SUM(S.NET_AMOUNT),
ROUND(STDDEV(S.NET_AMOUNT),2) AS STD_DEV
--(SELECT COUNT OF NET_AMOUNT < = 1$ FROM PFI_FACT_SALES GROUPED BY THE SAME P.PRODUCT_NUMBER) AS CNT
FROM PFI_DIM_PRODUCT P
JOIN PFI_FACT_SALES S
ON P.PRODUCT_PK_ID = S.PRODUCT_PK_ID
WHERE P.PRODUCT_NUMBER = 'ABC'
GROUP BY P.PRODUCT_NUMBER, P.PRODUCT_DESCRIPTION;
This is the part I am not able to figure out -
(SELECT COUNT OF NET_AMOUNT < = 1$ FROM PFI_FACT_SALES GROUPED BY THE SAME P.PRODUCT_NUMBER) AS CNT
What would be the best way to get the necessary row level data group by product number & product description?
Thanks.
One way is with a correlated subquery:
SELECT P.PRODUCT_NUMBER, P.PRODUCT_DESCRIPTION, SUM(S.NET_AMOUNT),
ROUND(STDDEV(S.NET_AMOUNT), 2) AS STD_DEV ,
(SELECT COUNT(*)
FROM PFI_FACT_SALES s2
WHERE s2.PRODUCT_PK_ID = s.PRODUCT_PK_ID AND
NET_AMOUNT <= 1
) as CNT
FROM PFI_DIM_PRODUCT P JOIN
PFI_FACT_SALES S
ON P.PRODUCT_PK_ID = S.PRODUCT_PK_ID
WHERE P.PRODUCT_NUMBER = 'ABC'
GROUP BY P.PRODUCT_NUMBER, P.PRODUCT_DESCRIPTION;
I'm pretty sure that you can also do this with a conditional windowed sum:
SELECT P.PRODUCT_NUMBER, P.PRODUCT_DESCRIPTION, SUM(S.NET_AMOUNT),
ROUND(STDDEV(S.NET_AMOUNT), 2) AS STD_DEV,
SUM(CASE WHEN NET_AMOUNT <= 1 THEN 1 ELSE 0 END) OVER (PARTITION BY s.PRODUCT_PK_ID) as CNT
FROM PFI_DIM_PRODUCT P JOIN
PFI_FACT_SALES S
ON P.PRODUCT_PK_ID = S.PRODUCT_PK_ID
WHERE P.PRODUCT_NUMBER = 'ABC'
GROUP BY P.PRODUCT_NUMBER, P.PRODUCT_DESCRIPTION;

Return first result only for each unique result

I am having some trouble with duplicating results in SQL Server 2005. I have previously used the ROW NUMBER function to display my query results, but I cannot get the query below to only display rownum 1:
SELECT *
FROM (SELECT l.insbilleddate, l.pickupdate, l.patientname, l.inscompanyname AS Payor, l.tripid,
l.sales, l.cost, l.sales-l.cost AS Profit, l.profitpct AS 'Profit Pct', u.pUPFName + ' ' +
u.pUPLName AS Dispatcher, ROW_NUMBER() OVER (PARTITION BY l.tripid ORDER BY d.trDispatchDate
ASC) AS rownum
FROM pUsersPrinters u
INNER JOIN TranslationDispatch d
INNER JOIN v_OLAPdataTR l ON d.trTripid = l.tripid ON u.pUP_id = d.trDispatchedBy
GROUP BY l.insbilleddate, l.pickupdate, l.patientname, l.inscompanyname, l.tripid, l.sales,
l.cost, l.profitpct, u.pUPFName, u.pUPLName, d.trDispatchDate
HAVING l.insbilleddate >= '6/1/2014' And l.insbilleddate < '7/1/2014' AND l.cost > '0' AND
l.profitpct < '30') q1
WHERE rownum = 1
ORDER BY q1.profitpct
The TranslationDispatch table adds a line each time a user dispatches a trip. If a trip needs to be reassigned the database does not overwrite the original dispatcher, instead it adds another line with the userID, tripID, and dispatch date. The d.trTripid = l.tripid comparison causes the trip to show for each dispatcher that marks it.
As an example, results show as:
TripID trDispatchedBy trDispatchDate
1234 Carlos 6/25/2014 10:00
1234 Tim 6/25/2014 10:02
...but I only want to display Carlos, as he dispatched the trip first.
EDIT: I've adjusted the query above with the help of #Vulcronos to make it work, by adding a table alias (q1) and making the rownum = '1' into rownum = 1 to correctly display my final result.
I would try:
ROW_NUMBER () OVER ( PARTITION BY l.insbilleddate, l.pickupdate, l.patientname,
l.inscompanyname, l.tripid, l.sales, l.cost, l.profitpct, u.pUPFName, u.pUPLName,
d.trDispatchDate ORDER BY trDispatchDate ASC)
This should give you a row number of one on every groups earliest dispatch date. Then you can wrap your whole query in:
select *
from (my_query)
where rownum = 1
How about adding "TOP 1" to the outside query
SELECT TOP 1 *
FROM(SELECT L.Insbilleddate,
L.Pickupdate,
L.Patientname,
L.Inscompanyname AS Payor,
L.Tripid,
L.Sales,
L.Cost,
L.Sales - L.Cost AS Profit,
L.Profitpct AS 'Profit Pct',
U.Pupfname + ' ' + U.Puplname AS Dispatcher,
ROW_NUMBER()OVER(PARTITION BY L.Tripid ORDER BY D.Trdispatchdate ASC)AS Rownum
FROM Pusersprinters U
INNER JOIN Translationdispatch D
INNER JOIN V_Olapdatatr L ON D.Trtripid = L.Tripid ON U.Pup_Id = D.Trdispatchedby
GROUP BY L.Insbilleddate,
L.Pickupdate,
L.Patientname,
L.Inscompanyname,
L.Tripid,
L.Sales,
L.Cost,
L.Profitpct,
U.Pupfname,
U.Puplname,
D.Trdispatchdate
HAVING L.Insbilleddate >= '6/1/2014'
AND L.Insbilleddate < '7/1/2014'
AND L.Cost > '0'
AND L.Profitpct < '30') A
ORDER BY A.Profitpct;

SQL GROUP BY AND VALUE AND NON UNIQUE VALUES

This is my SQL:
SELECT *
FROM (
SELECT DISTINCT real_dep_date,
real_price,
resort_name,
season_id,
min_occ,
free_sell,
MIN(real_price) OVER (PARTITION BY resort_name,real_dep_date) AS min_price
FROM deals_panel_view
WHERE ([1pax_disc] = [1pax_disc])
AND (real_dep_date >= season_start)
AND (season_name = 'winter 2012')
AND (chalet_url <> '')
AND (real_price <> 0)
AND (real_dep_date <= season_end)
AND (combined_chalet = 0)
AND (availability_spaces <> 0)
) deals_panel_view
WHERE min_price = real_price
This works but what happens is I get 3 results for a certain resort. This is because there are 3 chalets that are exactly the same.
I want to only show one, so I guess I would use a limit, but I don't know where.
I am using SQL Server 2005.
Any help would be great.
Try with this...
Select real_dep_date,
real_price,
resort_name,
season_id,
min_occ,
free_sell,
min_price FROM (SELECT ROW_NUMBER() over (PARTITION BY resort_name,real_dep_date ORDER BY resort_name) as ROW,*
FROM (
SELECT DISTINCT real_dep_date,
real_price,
resort_name,
season_id,
min_occ,
free_sell,
MIN(real_price) OVER (PARTITION BY resort_name,real_dep_date) AS min_price
FROM deals_panel_view
WHERE ([1pax_disc] = [1pax_disc])
AND (real_dep_date >= season_start)
AND (season_name = 'winter 2012')
AND (chalet_url <> '')
AND (real_price <> 0)
AND (real_dep_date <= season_end)
AND (combined_chalet = 0)
AND (availability_spaces <> 0)
) deals_panel_view
WHERE min_price = real_price
) Temp
where Row = 1