Joining tables inflates number values - sql

Here is my query, I have different account values (the accValByProd table) that I want to add to my table by their product type. If I just select the accValByProd table by itself the numbers are accurate, but when I join it with the billing table the numbers become much larger than they should be.
As you can see since I need to take the MAX of values in the billing table and then SUM them in the final calculation, I can't just do that in the final SELECT (unless there's a way to do that?). Any help is appreciated I'm not quite sure what I'm doing wrong.
WITH billing AS
( SELECT
bh.debit_account_id,
bh.period_start_date,
bh.period_end_date,
bh.a_id,
bh.account_value,
bh.platform_fee
FROM
billing_history bh
WHERE
-- LESS than same day following year includes any
-- possible time portion if so part of.
bh.period_start_date >= '2020-07-01'
and bh.period_end_date < '2021-07-01'
and bh.a_fee != 0
),
acc_prods AS
(
SELECT
a.account_id,
a.product_id,
CASE WHEN p.product_type = 3 THEN 'FSP'
WHEN p.product_type = 6 THEN 'APM'
WHEN p.product_type = 13 THEN 'UMA'
ELSE 'Unknown' END product_type,
a.a_id
FROM
account a
LEFT JOIN product p
ON a.product_id = p.product_id
WHERE
-- which table alias, should never leave blind
-- assumption here is "Account" table (alias a)
a.close_date IS NULL
OR a.close_date >= GETDATE()
),
accounts AS (
SELECT
a.account_id,
a.a_id,
a.customer_id,
a.close_date
FROM
account a
),
accValByProd as
(
SELECT
bh.debit_account_id AS deb_id,
bh.period_end_date,
MAX(bh.account_value) AS acc_val,
bh.a_id,
ISNULL(ap.product_type, 'Unknown') AS prod_type
FROM
billing_history bh
LEFT JOIN acc_prods ap
ON bh.debit_account_id = ap.account_id
WHERE
bh.period_end_date = '2021-06-30'
GROUP BY
bh.debit_account_id,
bh.period_end_date,
bh.a_id,
ap.product_type
)
SELECT DISTINCT
ad.ad_id,
ad.fname + ' ' + ad.middle + ' ' + ad.lname 'full name',
accValByProd.prod_type AS 'product type',
COUNT(DISTINCT billing.debit_account_id) AS 'number of accounts',
SUM(accValByProd.acc_val) AS 'product aum',
SUM(CASE WHEN DATEDIFF(DAY, billing.period_start_date, billing.period_end_date) > 31
THEN billing.platform_fee ELSE 0 END) AS 'fees'
FROM
advisor ad
JOIN billing
ON ad.a_id = billing.a_id
JOIN accounts
ON billing.debit_account_id = accounts.account_id
JOIN accValByProd
ON billing.debit_account_id = accValByProd.deb_id
WHERE
1=1
and ( ad.termination_date IS NULL
OR ad.termination_date >= GETDATE())
AND ( accounts.close_date IS NULL
OR accounts.close_date >= '2021-06-30')
GROUP BY
ad.a_id,
ad.fname,
ad.middle,
ad.lname,
accValByProd.prod_type
Here are the expected results for a_id 6835 (plus the other information)
a_id product aum product type
---- ------------ -------------
6835 7861895.23 APM
6835 47059722.64 FSP
6835 9816992.32 UMA
6835 528930.47 Unknown
And here are the actual results:
a_id product aum product type
---- ------------ -------------
6835 45447953.20 APM
6835 203942000.07 FSP
6835 77678383.30 UMA
6835 1706276.86 Unknown

Related

Not does not exclude query info

I have a really long query and I'm finding that my NOT is not excluding what's in parenthesis after the NOT.
I saw Exclude and where not exists, but I'd have to re-select for that, and there's too many complicatedly joined tables in what I selected already, plus one table is very big and takes a long time to select what I have already, so I can't re-select because it will make the query take too long. How do I get this exclusion to work?
INSERT INTO #UNeedingC(id, CASEID, firstname, lastname, userid, AGEOFNOTIFICATION, DATETIMEDECISIONMADE, DELEGATESYSTEM, Person_id, request_type_id, service_place_id, status_summary, externalUserId, subject, onDate, externalPersonId, externalSystemId)
select distinct
c.id
,uc.case_id
,t_case.FIRSTNAME as first
,t_case.LASTNAME as last
,t_case.user_id as userid
,CONVERT(VARCHAR, DATEDIFF(dd, SC.status_change_date, GETDATE())) + ' Day(s) ' + CONVERT(VARCHAR, DATEDIFF(hh, SC.status_change_date, GETDATE()) % 24) + ' Hour(s) ' as [AGE OF NOTIFICATION]
,SC.status_change_date AS [DATE TIME DECISION MADE]
,[ckoltp_sys].DBO.ckfn_GetStringLocaleValue(152,9,uc.delegate_system,50,0) AS [DELEGATESYSTEM]
,c.person_id
,uc.request_type_id ------
,uc.service_place_id
,uc.status_summary
,eou.external_id
,c.tzix_id+' '+[ckoltp_sys].dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0)+' type' AS subject
,dateadd( hour,41,dateadd(day,0,datediff(d,0,sc.status_change_date)) ) AS onDate
,emd.externalId externalPersonId
,eou.system_id as externalSystemId
--,u.disable
from
#tempC t_case with (NOLOCK)
inner join dbo.org_case c with (nolock) ON t_case.Person_id=c.Person_id
INNER JOIN dbo.org_2_case uc with (NOLOCK) ON uc.case_id=c.id
inner JOIN dbo.ORG_LOS S WITH (NOLOCK) ON S.case_id = UC.case_id
inner JOIN dbo.ORG_EXTENSION SC WITH (NOLOCK) ON SC.los_id= S.id
inner join dbo.org_user u with (NOLOCK) on u.id=t_case.user_id
inner join dbo.org_person op with (NOLOCK) on op.id=c.Person_id
inner JOIN dbo.u_person_concept_value MC ON MC.CID = op.cid --this is the slow table
inner join dbo.EXTERNAL_ORG_USER_DATA eou with (NOLOCK) ON eou.org_user_id = t_case.user_id
inner join dbo.EXTERNAL_person_DATA emd with (NOLOCK) ON emd.CID = op.cid --op.id --?
WHERE
DATEDIFF(day, SC.status_change_date , GETDATE()) <= 2
AND
u.disable <> 1
AND
( --(denied/approved)
dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0) = 'Denied'
OR
(dbo.ckfn_GetStringLocaleValue(148,9,uc.status_summary,5,0) in( 'Fully Approved', 'Partially Approved'))
)
AND
(
(
ISNULL(uc.request_type_id,'') in( 12)
AND DATEDIFF(month, SC.status_change_date , GETDATE()) <= 2
)
OR
(
ISNULL(uc.request_type_id,'') in( 10,11)
)
--OR
--(
-- --exclude this
-- (
-- MC.concept_id = '501620' --general val1 (1000/1001)
-- AND
-- (C.ID in (select case_id from #CASES where str_value in ('1000','1001'))
-- AND (uc.service_place_id = 31 OR uc.service_place_id = 32))
-- ) --not
--) --or
)--AND
AND
(t_case.firstname not like '%external%' and t_case.lastname not like '%case manager%')
AND
(
C.ID in (select case_id from #CASES where concept_id='501620')--MC.concept_id = '501620'
)
--overall around AND (denied/approved)--
and DBO.ckfn_GetStringLocaleValue(152,9,uc.delegate_system,50,0) in ('AP','CA')
AND NOT --this not is not working...this appears in query results
(
--exclude these
(
MC.concept_id = '501620'
AND
(C.ID in (select case_id from #CASES where str_value in ('1000','1001'))
AND (uc.service_place_id = 31 OR uc.service_place_id = 32))
) --not
) --
select * from #UNeedingC
results show what is excluded:
id caseid firstname lastname userid ageofNotification Datetimedecisionmade DelegateSys Person_id request_type_id service_place_id status_summary externalUserId subject
onDate externalPersonId externalSystemId
000256200 256200 Sree Par 1234 0 Apr 5 CA
4270000 11 31 3 sparee 000256200 Fully Approved tested Ad 2021-04-06 17:00 363000 2
My question: do you know why the NOT is not working and how I can get this to exclude without another select? See "this not is not working" comment. I searched online but only found exclude and where not exists, which require another select, which I don't want.
I think I figured it out: "NOT acts on one condition. To negate two or more conditions, repeat the NOT for each condition,"
from not on two things.
This seems to work:
...
AND
--exclude these
(
MC.concept_id = '501620' --general val1 (1000/1001)
AND
(C.ID not in (select case_id from #CASES where str_value in ('1000','1001'))
AND (uc.service_place_id not in ('31','32')))
) --not

SUBQUERY WITH SAME TABLE

I have a table that contains :
ID_Magasin: 001 for wharehouse, c01 for a magasin1, c02 for magasin 2, ..
Qte_Physique: the quantity number of an article
id_article: code article
lib_article: article designation
I want a query first, bring all the quantity of articles for each magasin.
second, in the same query I want to add a new column to display the quantity of the same article in the datawherhouse.
If I understand correctly, you can do this with a window function:
select d.*
from (select d.*,
sum(case when id_magasin = '001' then Qte_Physique else 0 end) over (partition by id_article) as wharehouse_qte
from dispo d
) d
where id_magasin <> '001';
Your subquery is not correlated to the main query. I.e. it is lacking the condition which product to look at.
select
gq_depot,
gq_article,
gq_physique,
(
select warehouse.gq_physique
from dispo warehouse
where warehouse.gq_depot = '001'
and warehouse.gq_article = magasin.gq_article
) as wh_physique
from dispo magasin
where gq_depot <> '001'
order by gq_depot, gq_article;
You can do the same with a join:
select
magasin.gq_depot,
magasin.gq_article,
magasin.gq_physique,
warehouse.gq_physique as wh_physique
from dispo magasin
left join dispo warehouse on warehouse.gq_article = magasin.gq_article
and warehouse.gq_depot = '001'
where magasin.gq_depot <> '001'
order by magasin.gq_depot, magasin.gq_article;
For readability you may use WITH clauses, if your DBMS features them:
with warehouse as (select * from dispo where gq_depot = '001')
, magasin as (select * from dispo where gq_depot <> '001')
select
magasin.gq_depot,
magasin.gq_article,
magasin.gq_physique,
warehouse.gq_physique as wh_physique
from magasin
left join warehouse on warehouse.gq_article = magasin.gq_article
order by magasin.gq_depot, magasin.gq_article;
Above queries only work correctly, if gq_depot + gq_article are unique in the table (e.g. constituting the primary key). Otherwise you'd need aggregation to get total gq_physique per gq_depot + gq_article.

Combining two tables including rows not found in other table, substituting values in column

I have two tables made from the following two queries:
SELECT t3.PatientID, SUM(t3.Fee) as total FROM
(SELECT t1.TestID, t2.PatientID, t1.Fee FROM
(SELECT Test.TestID, Test.Fee FROM MedicalTest AS Test) AS t1,
(SELECT T.TestID, T.PatientID FROM Take AS T) AS t2
WHERE t1.TestID = t2.TestID
ORDER BY t2.PatientID) AS t3
GROUP BY t3.PatientID
ORDER BY total DESC;
Which gives me a table of patient IDs and how much they have spent on tests, a portion of the table looks like this:
PATIENTID TOTAL
----------- ---------------------------------
99642131 550.00
99631255 440.00
99665378 430.00
99627956 310.00
99657423 280.00
99641125 260.00
99630025 230.00
99648682 230.00
My other query:
SELECT DISTINCT D.PatientID FROM Diagnose AS D
WHERE D.PhysicianID IN (
SELECT P.PhysicianID FROM Physician AS P
WHERE P.HName = 'Specific Hospital'
AND P.DName = 'Intensive Care Unit');
Returns to me a list of Patient IDs who are under the care of a specific physician. A portion of the table:
PATIENTID
-----------
99615376
99618797
99620783
99620882
99621221
I am trying to create a resultant table that contains the patient IDs from the second table as well as how much they have spent on medical tests from the first table. Some patients from the second table have not taken any tests in which case, I would like the table to simply give 0 for the total column, however, my attempt at combining the tables only gives me the patients who have taken tests:
SELECT t5.PatientID, t4.total FROM
(SELECT t3.PatientID, SUM(t3.Fee) as total FROM
(SELECT t1.TestID, t2.PatientID, t1.Fee FROM
(SELECT Test.TestID, Test.Fee FROM MedicalTest AS Test) AS t1,
(SELECT T.TestID, T.PatientID FROM Take AS T) AS t2
WHERE t1.TestID = t2.TestID
ORDER BY t2.PatientID) AS t3
GROUP BY t3.PatientID
ORDER BY total DESC) AS t4,
(SELECT DISTINCT D.PatientID FROM Diagnose AS D
WHERE D.PhysicianID IN (
SELECT P.PhysicianID FROM Physician AS P
WHERE P.HName = 'Specific Hospital'
AND P.DName = 'Intensive Care Unit')) AS t5
WHERE t5.PatientID = t4.PatientID;
Resultant table:
PATIENTID TOTAL
----------- ---------------------------------
99642131 550.00
99665378 430.00
99627956 310.00
How can I include the patients from table 2 that have not taken tests and enter 0 in their total column?
I managed to write the following query:
SELECT DISTINCT D.PatientID, COALESCE(total, '0') AS finalTotal
FROM Diagnose AS D
LEFT JOIN (
SELECT T.PatientID, SUM(M.Fee) AS total
FROM Take AS T, MedicalTest AS M
WHERE T.TestID = M.TestID
GROUP BY T.PatientID
) AS t1
ON t1.PatientID = D.PatientID
WHERE D.PhysicianID IN (
SELECT P.PhysicianID FROM Physician AS P
WHERE P.HName = 'Specific Hospital'
AND P.DName = 'Intensive Care Unit')
ORDER BY finalTotal DESC;
I use COALESCE(total, '0') with my LEFT JOIN to input 0 on the rows where no medical tests were done. This lead me to my desired output:
PATIENTID FINALTOTAL
----------- ------------------------------------------
99642131 550.00
99665378 430.00
99627956 310.00
99615376 0
99618797 0
99620783 0
99620882 0
99621221 0
99642157 0
99655482 0
99664061 0

Major issues with a query

I have a query
SELECT
ZEML.ICC_CODE AS ICC_CODE
,SUM(CS.TOT_HOURS) AS TOT_HOURS
,SUM(CS.NUM_INCIDENT_ALL) AS NUM_INCIDENTS
,(VALUE(FLOAT(SUM(CS.NUM_INCIDENT_ALL)) * 200000 / SUM(TOT_HOURS)
,0)) AS INC_RATE
FROM TR.CLAIMS_SUMM CS
INNER JOIN TR.LOCATION_MASTER LM
ON LM.LOCATION = CS.LOCATION
AND CS.LOCATION < '900'
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE = 'District'
LEFT JOIN TR.LOCATION_ASSIGNMENTS TERRITORY
ON TERRITORY.LOCATION = LM.LOCATION
AND TERRITORY.ASSIGNMENT_TYPE = 'Territory'
LEFT JOIN TR.EMPL_CLAIMS ZEML
ON CS.LOCATION = ZEML.LOCATION
AND ZEML.TYPE = 'WC'
AND ZEML.STATUS <> 'V'
AND ZEML.CLAIM_ACTION NOT IN ('D','F','I','H')
WHERE CS.DW_DATE BETWEEN '01/01/2014'
AND '05/31/2014'
AND (MONTH(ZEML.DATE_OF_INCIDENT) = MONTH(CS.DW_DATE)
AND YEAR(ZEML.DATE_OF_INCIDENT) = YEAR(CS.DW_DATE))
GROUP BY ZEML.ICC_CODE
UNION
SELECT
'OTHER' AS ICC_CODE
, 0 AS TOT_HOURS
, 0 AS NUM_INCIDENTS
, 0 AS INC_RATE
FROM SYSIBM.SYSDUMMY1
WHERE 1 = 1
ORDER BY 1
in my union where I made an other I want to select everything else from the tr.empl_claims table and store it in the other from the union because this is what I have many other ICC codes without incidents on them and I am doing calculations on our incident rate and hourse based off of all the data but my query right now is only selecting the ones that currently is having incidents which is throwing off my calculations.
From your use of FROM SYSIBM.SYSDUMMY1 I believe you are using DB2 database. If yes, you can use CTE (common table expression) to achieve the desired result like
WITH cte1 AS
(
SELECT
ZEML.ICC_CODE AS ICC_CODE
,SUM(CS.TOT_HOURS) AS TOT_HOURS
,SUM(CS.NUM_INCIDENT_ALL) AS NUM_INCIDENTS
,(VALUE(FLOAT(SUM(CS.NUM_INCIDENT_ALL)) * 200000 / SUM(TOT_HOURS)
,0)) AS INC_RATE
FROM TR.CLAIMS_SUMM CS
... <rest of the code> ...
)
select * from cte1
UNION ALL
SELECT
ICC_CODE
, 0 AS TOT_HOURS
, 0 AS NUM_INCIDENTS
, 0 AS INC_RATE
FROM TR.EMPL_CLAIMS
WHERE ICC_CODE NOT IN
(
SELECT distinct ICC_CODE
FROM cte1
)
ORDER BY 1
SideNote: You are joining the same table LOCATION_ASSIGNMENTS twice (as below) which is not needed.
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE = 'District'
LEFT JOIN TR.LOCATION_ASSIGNMENTS TERRITORY
ON TERRITORY.LOCATION = LM.LOCATION
AND TERRITORY.ASSIGNMENT_TYPE = 'Territory'
This can be transformed to below using a IN operator
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE IN ('District', 'Territory')
See more about Common Table Expression in DB2 Here.
Hope this helps.

I want SQLplus count(*) to return zero-values

I'm using Oracle 10.2 and have the following query:
select h.company, count(*)
from history h
where h.status = '2'
and h.substatus = '0'
and h.timestamp > '2012-01-01'
and h.timestamp < '2012-02-01'
group by h.company
having (h.company = 'AAA')
or (h.company = 'BBB')
or (h.company = 'CCC')
order by h.company
This will count the amount of times any customer from the companies AAA, BBB or CCC has reached a specific point (status = 2).
Presume no (zero) customers from BBB did so, the result will come back with 2 rows of count(AAA and CCC).
What I want: I wish for the query to return me rows for all 3 companies, even tho the count is zero.
Sorry for the odd layout of the query. It's made to work with MS Excel as well.
Edit: Sorry.. Too little caffeine. changed "Customer" in the later half of the query to "Company".
Clarification: A customer is made unique by combining "h.company" and "h.customer" (or by using the same method in customer-table (customer c), like "c.company" and "c.customer"
Edit 2: Updated code.
select c.company, count(*)
from companyregister c
left join history h on h.company = c.company
where h.status = '2'
and h.substatus = '0'
and h.timestamp > '2012-01-01'
and h.timestamp < '2012-02-01'
group by c.company
having (c.company = 'AAA')
or (c.company = 'BBB')
or (c.company = 'CCC')
order by c.company
Both sets of code from above will yield two rows as follows:
AAA 630
CCC 3020
I would like to have BBB represented, but since they have zero rows in history, they don't show.
Make a left join on the customer table. I don't know what you have named it, but like this:
select c.company, count(h.customer)
from customer as c
left join history as h on h.customer = c.customer
...
Another alternative is to use a condition when counting. I'm not sure if there is any other condition that you need along with the status, but something liket this:
select company, sum(case status when '2' then 1 else 0 end)
from history
where substatus = '0'
and timestamp > '2012-01-01'
and timestamp < '2012-02-01'
and customer in ('AAA', 'BBB', 'CCC')
group by customer
order by customer