Why doesn't my query return correct results? - sql

I have used these Temp table to return total no of SOlved Cases and Total Number of Pending Cases from same table grouped by DIstrict e.g.
District TotalSolvedCases TotalPendingCases
A 3 1
B 8 6
C 7 1
I have done this but this doesn't return correct Result
SELECT *
INTO #Table1
FROM (
SELECT COUNT(Cases.pk_Cases_CaseID) TotalCases,
Districts.DistrictName
FROM Cases
INNER JOIN ConcernedOffices ON ConcernedOffices.pk_ConcernedOffices_ID = Cases.fk_ConcernedOffices_Cases_ConcernedOfficeID
INNER JOIN Districts ON Districts.pk_Districts_DistrictID = ConcernedOffices.fk_Districts_ConcernedOffices_DistrictID
INNER JOIN CaseHearings ON CaseHearings.fk_Cases_CaseHearings_CaseID = Cases.pk_Cases_CaseID
WHERE CaseHearings.IsClosingDate = 1
GROUP BY Districts.DistrictName
) d
SELECT *
INTO #Table2
FROM (
SELECT COUNT(Cases.pk_Cases_CaseID) TotalPedningCases,
Districts.DistrictName
FROM Cases
INNER JOIN ConcernedOffices ON ConcernedOffices.pk_ConcernedOffices_ID = Cases.fk_ConcernedOffices_Cases_ConcernedOfficeID
INNER JOIN Districts ON Districts.pk_Districts_DistrictID = ConcernedOffices.fk_Districts_ConcernedOffices_DistrictID
INNER JOIN CaseHearings ON CaseHearings.fk_Cases_CaseHearings_CaseID = Cases.pk_Cases_CaseID
WHERE CaseHearings.IsClosingDate = 0
GROUP BY Districts.DistrictName
) d
SELECT #Table1.TotalCases AS TotalSolvedCases,
#Table2.TotalPedningCases,
#Table1.DistrictName
FROM #Table1
INNER JOIN #Table2 ON #Table2.DistrictName = #Table1.DistrictName
GROUP BY #Table1.TotalCases,
#Table2.TotalPedningCases,
#Table1.DistrictName

You only need one SELECT, use case expressions to do conditional counting:
SELECT COUNT(case when CaseHearings.IsClosingDate = 1 then 1 end) TotalCases,
COUNT(case when CaseHearings.IsClosingDate = 0 then 1 end) TotalPedningCases,
Districts.DistrictName
FROM Cases
INNER JOIN ConcernedOffices ON ConcernedOffices.pk_ConcernedOffices_ID = Cases.fk_ConcernedOffices_Cases_ConcernedOfficeID
INNER JOIN Districts ON Districts.pk_Districts_DistrictID = ConcernedOffices.fk_Districts_ConcernedOffices_DistrictID
INNER JOIN CaseHearings ON CaseHearings.fk_Cases_CaseHearings_CaseID = Cases.pk_Cases_CaseID
GROUP BY Districts.DistrictName

Related

SQL / Oracle SQL Code for looking data from other tables

How to write query to get data from other table for each columns in existing table.
You can left join three times on system_code:
select
d.id,
s_cat.full_name cat_code_full_name,
s_group.full_name group_code_full_name,
s_other.full_name other_code_full_name
from data_table d
left join system_code s_cat
on s_cat.value = d.cat_code and s.code = 1
left join system_code s_group
on s_group.value = d.group_code and s_group.code = 2
left join system_code s_other
on s_other.value = d.other_code and s_other.code = 3
To avoid repeating the joins, an alternative solution is to do conditional aggregation:
select
d.id,
max(case when s.value = d.cat_code and s.code = 1 then s.full_name end) cat_code_full_name,
max(case when s.value = d.group_code and s.code = 2 then s.full_name end) group_code_full_name,
max(case when s.value = d.other_code and s.code = 3 then s.full_name end) other_code_full_name
from data_table d
left join system_code s on s.value in (d.cat_code, d.group_code, d.other_code)
gtoup by d.id
I guess the problem you are facing here is, how to get full name for all 3 columns. 1 of the method is to join SYSTEM_CODE table thrice -
SELECT DT.ID
,SC1.FULL_NAME CAT_CODE_FULL_NAME
,SC2.FULL_NAME GROUP_CODE_FULL_NAME
,SC3.FULL_NAME OTHER_CODE_FULL_NAME
,DT.PRODUCT
FROM DATA_TABLE DT
JOIN SYSTEM_CODE SC1 ON SC1.VALUE = DT.CAT_CODE
JOIN SYSTEM_CODE SC2 ON SC2.VALUE = DT.CAT_CODE
JOIN SYSTEM_CODE SC3 ON SC3.VALUE = DT.CAT_CODE

Single-row subquery returns more than one row - Case statement

My following code returns the error stated in the title, however the error does not show when the case statement is ran by itself.
I've tried to dismantle the case statement, however this isn't my query but IS being used elsewhere, i'm wondering how they manage to get it to return rows in its current state.
SELECT DISTINCT V55."INPUTSPECNAME",
V55."FKMATERIAL",
V55."INPUTQUANTITYVALUE",
B.ABBREVIATION,
(CASE
WHEN z.COST IS NULL
THEN (SELECT DISTINCT (CASE
WHEN MatOut_D.PERVALUEQUANTITY > 0 THEN
ROUND(MatOut_D.PRICE /
MatOut_D.PERVALUEQUANTITY /
10 /
MatOut_E.USDCONVERSIONFACTOR *
C.USDCONVERSIONFACTOR, 5)
ELSE 0
END)
FROM V55_FORMULATIONJOINMATOUTPUT MatOut_B,
V55_FORMULATIONINPUTOUTPUT MatOut_C,
THEORETICALCOSTS MatOut_D,
COMMONCURRENCIES MatOut_E,
UOMML MatOut_F
WHERE MatOut_B.FKREFERENCEDMATERIAL = V55.FKMATERIAL
AND MatOut_B.FKOWNER = MatOut_C.FKOWNER
AND MatOut_C.FORMULATIONOUTPUTPKID = MatOut_D.FKPARENT
AND MatOut_D.FKCURRENCY = MatOut_E.PKID
AND MatOut_D.FKPERVALUEUOM = MatOut_F.FKUOM
AND MatOut_F.LANGID = 0)
ELSE ROUND(z.COST*100/D.USDCONVERSIONFACTOR*C.USDCONVERSIONFACTOR,5)
END) AS COST_100G
FROM V55_FORMULATIONINPUTOUTPUT V55
INNER JOIN UOM A
on V55.FKINPUTUOM = A.PKID
INNER JOIN UOMML B
on a.pkid = B.FKUOM
INNER JOIN DWBSpecificationRoots dwbRoot
on dwbRoot.fkOwner = V55.FKOWNER
INNER JOIN dwbSpecifications dwbSpec
ON dwbSpec.fkWorkingVersionParent = dwbRoot.pkid
LEFT OUTER JOIN specLegacySpecJoin y
on dwbSpec.fkdisplayedlegacyprofile = y.fklegacyprofileid
and y.fkspecid = V55.fkMaterial
LEFT OUTER join COSTITEMS z
on z.equivalent = y.equivalent
and z.fklegacyprofile = dwbSpec.fkdisplayedlegacyprofile
and z.FKSCRMENTITY = dwbSpec.FKSCRMSUPPLIERBASE
and z.COSTTYPE = dwbSpec.COSTTYPE
LEFT OUTER JOIN COMMONCURRENCIES C
ON C.PKID = dwbSpec.FKCURRENCY
LEFT OUTER JOIN COMMONCURRENCIES D
ON D.PKID = Z.FKCURRENCY
The problem is that the subquery in your CASE statement is returning multiple rows in some situations and as has been stated in the question's comments that's a no-no.
I suggest that you pull the subquery out of the CASE statement and make it a Common Table Expression, then join it into the query as you would any other table:
WITH cteSubexpr AS (SELECT DISTINCT MatOut_B.FKREFERENCEDMATERIAL,
(CASE
WHEN MatOut_D.PERVALUEQUANTITY > 0 THEN
ROUND(MatOut_D.PRICE /
MatOut_D.PERVALUEQUANTITY /
10 /
MatOut_E.USDCONVERSIONFACTOR *
C.USDCONVERSIONFACTOR, 5)
ELSE 0
END) AS CALC_QTY
FROM V55_FORMULATIONJOINMATOUTPUT MatOut_B
INNER JOIN V55_FORMULATIONINPUTOUTPUT MatOut_C
ON MatOut_C.FKOWNER = MatOut_B.FKOWNER
INNER JOIN THEORETICALCOSTS MatOut_D
ON MatOut_D.FKPARENT = MatOut_C.FORMULATIONOUTPUTPKID
INNER JOIN COMMONCURRENCIES MatOut_E
ON MatOut_E.PKID = MatOut_D.FKCURRENCY
INNER JOIN UOMML MatOut_F
ON MatOut_F.FKUOM = MatOut_D.FKPERVALUEUOM
WHERE MatOut_F.LANGID = 0)
SELECT DISTINCT V55.INPUTSPECNAME,
V55.FKMATERIAL,
V55.INPUTQUANTITYVALUE,
B.ABBREVIATION,
(CASE
WHEN z.COST IS NULL
THEN cs.CALC_QTY
ELSE ROUND(z.COST * 100 / D.USDCONVERSIONFACTOR * C.USDCONVERSIONFACTOR, 5)
END) AS COST_100G
FROM V55_FORMULATIONINPUTOUTPUT V55
INNER JOIN cteSubexpr cs
ON cs.FKREFERENCEDMATERIAL = V55.FKMATERIAL
INNER JOIN UOM A
on V55.FKINPUTUOM = A.PKID
INNER JOIN UOMML B
on a.pkid = B.FKUOM
INNER JOIN DWBSpecificationRoots dwbRoot
on dwbRoot.fkOwner = V55.FKOWNER
INNER JOIN dwbSpecifications dwbSpec
ON dwbSpec.fkWorkingVersionParent = dwbRoot.pkid
LEFT OUTER JOIN specLegacySpecJoin y
on dwbSpec.fkdisplayedlegacyprofile = y.fklegacyprofileid
and y.fkspecid = V55.fkMaterial
LEFT OUTER join COSTITEMS z
on z.equivalent = y.equivalent
and z.fklegacyprofile = dwbSpec.fkdisplayedlegacyprofile
and z.FKSCRMENTITY = dwbSpec.FKSCRMSUPPLIERBASE
and z.COSTTYPE = dwbSpec.COSTTYPE
LEFT OUTER JOIN COMMONCURRENCIES C
ON C.PKID = dwbSpec.FKCURRENCY
LEFT OUTER JOIN COMMONCURRENCIES D
ON D.PKID = Z.FKCURRENCY
Best of luck.

SQL correct query or not

given these relationships, how could you query the following:
The tourists (name and email) that booked at least a pension whose rating is greater than 9, but didn't book any 3 star hotel with a rating less than 9.
Is the following correct?
SELECT Tourists.name, Tourists.email
FROM Tourists
WHERE EXISTS (
SELECT id FROM Bookings
INNER JOIN Tourists ON Bookings.touristId=Tourists.id
INNER JOIN AccomodationEstablishments ON Bookings.accEstId=AccomodationEstablishments.id
INNER JOIN AccomodationTypes ON AccomodationEstablishments.accType=AccomodationTypes.id
WHERE AccomodationTypes.name = 'Pension' AND
AccomodationEstablishments.rating > 9
) AND NOT EXISTS (
SELECT id FROM Bookings
INNER JOIN Tourists ON Bookings.touristId=Tourists.id
INNER JOIN AccomodationEstablishments ON Bookings.accEstId=AccomodationEstablishments.id
INNER JOIN AccomodationTypes ON AccomodationEstablishments.accType=AccomodationTypes.id
WHERE AccomodationTypes.name = 'Hotel' AND
AccomodationEstablishments.noOfStars = 3 AND
AccomodationEstablishments.rating < 9
)
I would do this using aggregation and having:
SELECT t.name, t.email
FROM Bookings b INNER JOIN
Tourists t
ON b.touristId = t.id INNER JOIN
AccomodationEstablishments ae
ON b.accEstId = ae.id INNER JOIN
AccomodationTypes a
ON ae.accType = a.id
GROUP BY t.name, t.email
HAVING SUM(CASE WHEN a.name = 'Pension' AND ae.rating > 9 THEN 1 ELSE 0 END) > 0 AND
SUM(a.name = 'Hotel' AND ae.noOfStars = 3 AND ae.rating < 9 THEN 1 ELSE 0 END)= 0;
Your method also works, but you probably need t.id in the subqueries.

SQl Error : Each GROUP BY expression must contain at least one column that is not an outer reference [duplicate]

This question already has answers here:
Each GROUP BY expression must contain at least one column that is not an outer reference
(8 answers)
Closed 6 years ago.
I get this error
Each GROUP BY expression must contain at least one column that is not an outer reference
while running this query:
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN
#tmpInstallParts_Temp installpartdetails ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END
) = 1
INNER JOIN
partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN
partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN
partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y' AND
ima.ipp_ID IN (SELECT ipp.ipp_id
FROM partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp ON (ipp.ipp_id = tmp.InstallingPartIPPId OR
(CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1
)
GROUP BY
ima.ipp_id
Can someone help me?
This is the text of the query from the first revision of the question.
In later revisions you removed the last closing bracket ) and the query became syntactically incorrect. You'd better check and fix the text of the question and format the text of the query, so it is readable.
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1)
GROUP BY
ima.ipp_id
)
With this formatting it is clear now that there is a subquery with GROUP BY.
Most likely it is just a typo: you meant to write GROUP BY ipp.ipp_id instead of GROUP BY ima.ipp_id.
If you really wanted to have the GROUP BY not in a subquery, but in the main SELECT, then you misplaced the closing bracket ) and the query should look like this:
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END) = 1)
)
GROUP BY
ima.ipp_id
In any case, proper formatting of the source code can really help.
Group By ima.ipp_id
should be applicable to outer query. Because of incorrect placement of '(' it was applying to inner query.
Now after correcting the query,it's working fine without any issues.
Final Query is :
SELECT TOP 1
SUM(mla.total_current_attribute_value)
FROM
partstrack_machine_location_attributes mla (NOLOCK)
INNER JOIN #tmpInstallParts_Temp installpartdetails
ON mla.machine_sequence_id = installpartdetails.InstallKitToMachineSequenceId
AND (CASE WHEN mla.machine_side_id IS NULL THEN 1
WHEN mla.machine_side_id = installpartdetails.InstallKitToMachineSideId THEN 1 END ) = 1
INNER JOIN partstrack_mes_attribute_mapping mam (NOLOCK) ON mla.mes_attribute = mam.mes_attribute_name
INNER JOIN partstrack_attribute_type at (NOLOCK) ON mam.pt_attribute_id = at.pt_attribute_id
INNER JOIN partstrack_ipp_mes_attributes ima(NOLOCK) ON at.pt_attribute_id = ima.pt_attribute_id
WHERE
mla.active_ind = 'Y'
AND ima.ipp_ID IN
(
Select
ipp.ipp_id
FROM
partstrack_individual_physical_part ipp
INNER JOIN #tmpInstallParts_Temp tmp
ON (ipp.ipp_id = tmp.InstallingPartIPPId
OR (CASE WHEN tmp.InstallingPartIPKId = '-1' THEN 1 END ) =1)
)
GROUP BY ima.ipp_id
Thank you all.

Query for logistic regression, multiple where exists

A logistic regression is a composed of a uniquely identifying number, followed by multiple binary variables (always 1 or 0) based on whether or not a person meets certain criteria. Below I have a query that lists several of these binary conditions. With only four such criteria the query takes a little longer to run than what I would think. Is there a more efficient approach than below? Note. tblicd is a large table lookup table with text representations of 15k+ rows. The query makes no real sense, just a proof of concept. I have the proper indexes on my composite keys.
select patient.patientid
,case when exists
(
select c.patientid from tblclaims as c
inner join patient as p on p.patientid=c.patientid
and c.admissiondate = p.admissiondate
and c.dischargedate = p.dischargedate
where patient.patientid = p.patientid
group by c.patientid
having count(*) > 1000
)
then '1' else '0'
end as moreThan1000
,case when exists
(
select c.patientid from tblclaims as c
inner join patient as p on p.patientid=c.patientid
and c.admissiondate = p.admissiondate
and c.dischargedate = p.dischargedate
where patient.patientid = p.patientid
group by c.patientid
having count(*) > 1500
)
then '1' else '0'
end as moreThan1500
,case when exists
(
select distinct picd.patientid from patienticd as picd
inner join patient as p on p.patientid= picd.patientid
and picd.admissiondate = p.admissiondate
and picd.dischargedate = p.dischargedate
inner join tblicd as t on t.icd_id = picd.icd_id
where t.descrip like '%diabetes%' and patient.patientid = picd.patientid
)
then '1' else '0'
end as diabetes
,case when exists
(
select r.patientid, count(*) from patient as r
where r.patientid = patient.patientid
group by r.patientid
having count(*) >1
)
then '1' else '0'
end
from patient
order by moreThan1000 desc
I would start by using subqueries in the from clause:
select q.patientid, moreThan1000, moreThan1500,
(case when d.patientid is not null then 1 else 0 end),
(case when pc.patientid is not null then 1 else 0 end)
from patient p left outer join
(select c.patientid,
(case when count(*) > 1000 then 1 else 0 end) as moreThan1000,
(case when count(*) > 1500 then 1 else 0 end) as moreThan1500
from tblclaims as c inner join
patient as p
on p.patientid=c.patientid and
c.admissiondate = p.admissiondate and
c.dischargedate = p.dischargedate
group by c.patientid
) q
on p.patientid = q.patientid left outer join
(select distinct picd.patientid
from patienticd as picd inner join
patient as p
on p.patientid= picd.patientid and
picd.admissiondate = p.admissiondate and
picd.dischargedate = p.dischargedate inner join
tblicd as t
on t.icd_id = picd.icd_id
where t.descrip like '%diabetes%'
) d
on p.patientid = d.patientid left outer join
(select r.patientid, count(*) as cnt
from patient as r
group by r.patientid
having count(*) >1
) pc
on p.patientid = pc.patientid
order by 2 desc
You can then probably simplify these subqueries more by combining them (for instance "p" and "pc" on the outer query can be combined into one). However, without the correlated subqueries, SQL Server should find it easier to optimize the queries.
Example of left joins as requested...
SELECT
patientid,
ISNULL(CondA.ConditionA,0) as IsConditionA,
ISNULL(CondB.ConditionB,0) as IsConditionB,
....
FROM
patient
LEFT JOIN
(SELECT DISTINCT patientid, 1 as ConditionA from ... where ... ) CondA
ON patient.patientid = CondA.patientID
LEFT JOIN
(SELECT DISTINCT patientid, 1 as ConditionB from ... where ... ) CondB
ON patient.patientid = CondB.patientID
If your Condition queries only return a maximum one row, you can simplify them down to
(SELECT patientid, 1 as ConditionA from ... where ... ) CondA