Subquery Where clause invalid in select list - sql

I am trying to create a numerator(num) and denominator(den) column that I will later use to create a metric value. In my numerator column, I need to have a criteria that my denominator column does not have. When I add the where clause to my sub query, I am getting the error below. I do not want to add INRInRange to my Group By clause.
Column 'dbo.PersonDetailB.INRInRange' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."
SELECT
dbo.PersonDetailSpecialty.PracticeAbbrevName,
(SELECT COUNT(DISTINCT dbo.Problem.PID) WHERE PersonDetailB.INRInRange='True') AS num,
COUNT(DISTINCT dbo.Problem.PID) AS den
FROM
dbo.PersonDetailB
RIGHT OUTER JOIN
dbo.PersonDetailSpecialty ON dbo.PersonDetailB.PID = dbo.PersonDetailSpecialty.PID
LEFT OUTER JOIN
dbo.Problem ON dbo.PersonDetailSpecialty.PID = dbo.Problem.PID
GROUP BY
practiceabbrevname

Create a sub-query that counts PersonDetailB.INRInRange and LEFT OUTER JOIN it with the original query.
SELECT Main.PracticeAbbrevName, InRange.Num AS num, Main.den
FROM
(SELECT
dbo.PersonDetailSpecialty.PracticeAbbrevName,
COUNT(DISTINCT dbo.Problem.PID) AS den
FROM
dbo.PersonDetailB
RIGHT OUTER JOIN
dbo.PersonDetailSpecialty ON dbo.PersonDetailB.PID = dbo.PersonDetailSpecialty.PID
LEFT OUTER JOIN
dbo.Problem ON dbo.PersonDetailSpecialty.PID = dbo.Problem.PID
GROUP BY
practiceabbrevname) Main
LEFT OUTER JOIN
(SELECT practiceabbrevname, COUNT(DISTINCT dbo.Problem.PID) Num WHERE PersonDetailB.INRInRange='True' GROUP BY practiceabbrevname) InRange ON Main.practiceabbrevname = InRange.practiceabbrevname

The problem with this statement:
SELECT dbo.PersonDetailSpecialty.PracticeAbbrevName,
(SELECT COUNT(DISTINCT dbo.Problem.PID) WHERE PersonDetailB.INRInRange = 'True') AS num,
COUNT(DISTINCT dbo.Problem.PID) AS den
is that PersonDetailB.INRInRange1 doesn't have a unique value in each group. It is possible that it does. One method is to add it to the GROUP BY:
GROUP BY practiceabbrevname, PersonDetailB.INRInRange
Another method would use an aggregation function in the subquery:
SELECT dbo.PersonDetailSpecialty.PracticeAbbrevName,
(SELECT COUNT(DISTINCT dbo.Problem.PID) WHERE MAX(PersonDetailB.INRInRange) = 'True') AS num,
COUNT(DISTINCT dbo.Problem.PID) AS den

Join a separate table as a different name on the where criteria that was in the sub query.
SELECT PersonDetailSpecialty.PracticeAbbrevName,
COUNT(PDTRUE.PID) as num,
COUNT(dbo.Problem.PID) AS den
FROM dbo.PersonDetailSpecialty LEFT OUTER JOIN
dbo.PersonDetailB as PDTRUE ON dbo.PersonDetailSpecialty.PID = PDTRUE.PID and PDTRUE.INRInRange='True' LEFT OUTER JOIN
dbo.PersonDetailB ON dbo.PersonDetailSpecialty.PID = PersonDetailB.PID LEFT OUTER JOIN
dbo.Medicate ON dbo.PersonDetailSpecialty.PID = dbo.Medicate.PID LEFT OUTER JOIN
dbo.Problem ON dbo.PersonDetailSpecialty.PID = dbo.Problem.PID
GROUP BY PersonDetailSpecialty.PracticeAbbrevName
This is the relevant code needed in the FROM section
dbo.PersonDetailSpecialty LEFT OUTER JOIN dbo.PersonDetailB as PDTRUE
ON dbo.PersonDetailSpecialty.PID = PDTRUE.PID and PDTRUE.INRInRange='True'
This lets you add
COUNT(PDTRUE.PID) as num,
as a simple part of the overall select query

Related

Query for records count from shown rows

select lsd.lsd ,count(reading.infrastructure_id),type.infrastructure_type from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
Make the query as an in-line view and select count(*) from the in-line view
Eg:
select count(*) from(
select lsd.lsd
,count(reading.infrastructure_id)
,type.infrastructure_type
from public.cpreading_lsd lsd
left join cpreading_infrastructure infra on lsd.id = infra.lsd_id
left join public.cpreading_infrastructure_type type on type.id = infra.infrastructure_type_id
left join cpreading_cp_reading_entry reading on infra.id = reading.infrastructure_id
group by lsd.lsd,type.infrastructure_type
)x

SQL using SUM and INNER JOIN issue

I get this error when I try to execute the query shown below
Column 'dbo.Stock_Purchase.Supplier_ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Query:
SELECT
dbo.Stock_Purchase.*, dbo.Stock_Purchase_Details.*,
dbo.Supplier.*,
SUM(Stock_Purchase_Details.Discount) AS totaldis
FROM
dbo.Stock_Purchase
INNER JOIN
dbo.Stock_Purchase_Details ON dbo.Stock_Purchase.Purchase_ID = dbo.Stock_Purchase_Details.Purchase_ID
INNER JOIN
dbo.Supplier ON dbo.Stock_Purchase.Supplier_ID = dbo.Supplier.Supplier_ID
GROUP BY
Stock_Purchase.Purchase_ID
You can only include the column in the GROUP BY as a "bare" column in the SELECT. So:
SELECT p.Purchase_ID, sum(pd.Discount) as totaldis
FROM dbo.Stock_Purchase p INNER JOIN
dbo.Stock_Purchase_Details pd
ON p.Purchase_ID = pd.Purchase_ID INNER JOIN
dbo.Supplier s
ON p.Supplier_ID = s.Supplier_ID
GROUP BY p.Purchase_ID ;
Also notice how table aliases make the query easier to read, write, and understand.
If you do want all the details, you can use window functions:
SELECT p.*, pd.*, s.*,
SUM(pd.Discount) OVER (PARTITION BY p.Purchase_ID) as totaldis
FROM dbo.Stock_Purchase p INNER JOIN
dbo.Stock_Purchase_Details pd
ON p.Purchase_ID = pd.Purchase_ID INNER JOIN
dbo.Supplier s
ON p.Supplier_ID = s.Supplier_ID;

SQL oracle error on select inside select

This return single-row query subquery returns more than one row
select E.NO_ENCAN, E.NOM_ENC, TE.DESC_TYPE_ENC as TYPE_ENC,
(select sum(ITEM.MNT_VALEUR_ITE) from ENCAN left join ITEM on ITEM.NO_ENCAN = ENCAN.NO_ENCAN group by ENCAN.NO_ENCAN) as SOMME_ITEMS,
count(distinct INV.NOM_UTILISATEUR_INVITE) as NOMBRE_INVITES
from ENCAN E
left join TYPE_ENCAN TE on TE.CODE_TYPE_ENC = E.CODE_TYPE_ENC
left join INVITE INV on INV.NO_ENCAN = E.NO_ENCAN
group by E.NO_ENCAN, E.NOM_ENC, TE.DESC_TYPE_ENC
order by E.NO_ENCAN;
And if I add order by in the subquery, it returns a missing right parenthesis.
Anyone can give me any clues on what's going on?
By the way, I know that keyword/word are inversed uppercase/lowercase
You want a correlated subquery rather than a group by in the subselect. This also means that the subquery is not needed. So, this is probably what you are trying to write:
select E.NO_ENCAN, E.NOM_ENC, TE.DESC_TYPE_ENC as TYPE_ENC,
(select sum(ITEM.MNT_VALEUR_ITE)
from ITEM
where ITEM.NO_ENCAN = ENCAN.NO_ENCAN
) as SOMME_ITEMS,
count(distinct INV.NOM_UTILISATEUR_INVITE) as NOMBRE_INVITES
from ENCAN E left join
TYPE_ENCAN TE
on TE.CODE_TYPE_ENC = E.CODE_TYPE_ENC left join
INVITE INV
on INV.NO_ENCAN = E.NO_ENCAN
group by E.NO_ENCAN, E.NOM_ENC, TE.DESC_TYPE_ENC
order by E.NO_ENCAN;
Without knowing more about your schema and data, it looks to me like the issue is the 'group by ENCAN.NO_ENCAN'
I don't think you need the group by, or it is causing you issue.
If I am correctly understanding what you are trying to accomplish, I believe the subquery is unnecessary. You should just put an analytic on the SUM() call.
SELECT e.no_encan
,e.nom_enc
,te.desc_type_enc AS type_enc
,SUM(item.mnt_valeur_ite) OVER (PARTITION BY e.no_encan) somme_items
,COUNT(DISTINCT inv.nom_utilisateur_invite) AS nombre_invites
FROM encan e
LEFT JOIN type_encan te ON te.code_type_enc = e.code_type_enc
LEFT JOIN invite INV ON inv.no_encan = e.no_encan
GROUP BY e.no_encan, e.nom_enc, te.desc_type_enc
ORDER BY e.no_encan;
Details can be found here, although I would really suggest reading more about Analytic Functions in Oracle.
Your inner select statement is returning more than one row. Try adding a WHERE clause to limit your select to return one row.
select sum(ITEM.MNT_VALEUR_ITE) from ENCAN left join ITEM on ITEM.NO_ENCAN = ENCAN.NO_ENCAN
**WHERE ENCAN.NO_ENCAN = '1234'**
group by ENCAN.NO_ENCAN
I would do it like this:
with INVITE_ROLLUP as
(
select ENCAN.NO_ENCAN, sum(ITEM.MNT_VALEUR_ITE) as NOMBRE_INVITES
from ENCAN
left join ITEM on ITEM.NO_ENCAN = ENCAN.NO_ENCAN
group by ENCAN.NO_ENCAN
)
select
E.NO_ENCAN,
E.NOM_ENC,
TE.DESC_TYPE_ENC as TYPE_ENC,
INVITE_ROLLUP.NOMBRE_INVITES AS NOMBRE_INVITES
from ENCAN E
left join TYPE_ENCAN TE on TE.CODE_TYPE_ENC = E.CODE_TYPE_ENC
left join INVITE INV on INV.NO_ENCAN = E.NO_ENCAN
left join INVITE_ROLLUP ON E.NO_ENCAN = INVITE_ROLLUP.NO_ENCAN
group by E.NO_ENCAN, E.NOM_ENC, TE.DESC_TYPE_ENC
order by E.NO_ENCAN;
The Group by ENCAN.NO_ENCAN is causing the issue. Since you are not selecting that column, you don't need to group by that.

JOIN / LEFT JOIN conflict in SQL Server

I have a tricky query. I need to select all recent versions of 2 types of members of administrator groups. Here is the query:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
This query will return all the administrator groups. The next step will be getting the members of these groups. Since I have 2 types of memberships (Explicit, Computed), I will have to use a LEFT JOIN to make sure that I am not excluding any rows.
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
-- The JOIN bellow can be excluded but it is here just to clarify the architecture
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
The last piece in the puzzle is to get the latest version of each member. For that I will have to use JOIN to exclude older versions:
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
and
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The full query will be:
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN tblGroup_ComputedMember cm ON refMem.ObjectUID = cm.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
LEFT JOIN tblGroup_ExplicitMember em ON refMem.ObjectUID = em.GroupObjectID
JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ExplicitMember
GROUP BY ObjectID
) MostRecentEM ON MostRecentEM.MaxId = em.Id
The issue is clear: The 2 JOIN to exclude old versions are also applied to the select statement and clearly no rows are returned. What would be the best solution to escape such situation and to return the intended values?
SELECT refGroup.*
FROM tblSystemAdministratorGroups refGroup
JOIN tblGroup refMem ON refGroup.AttributeValue = refMem.ObjectUID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ComputedMember
) cm ON refMem.ObjectUID = cm.GroupObjectID and cm.ID = cm.maxID
LEFT JOIN (
select GroupObjectID, ID, max(ID) over (partition by ObjectID) as maxID
from tblGroup_ExplicitMember
) em ON refMem.ObjectUID = em.GroupObjectID and em.ID = em.maxID
where cm.ID = cm.MaxID
What about using LEFT join in your last two joins?
LEFT JOIN (
SELECT MAX([ID]) MaxId
FROM [OmadaReporting].[dbo].tblGroup_ComputedMember
GROUP BY ObjectID
) MostRecentCM ON MostRecentCM.MaxId = cm.Id
And then in Where clause filter values as:
WHERE MostRecentCM.MaxId IS NOT NULL
OR
MostRecentEM.MaxId IS NOT NULL

use field in sql join where clause

I am trying to write a crystal report using a sql statement because it runs much much faster. But I am having trouble with some of the linkings. I need to use the result of a link for criteria in subsequent links.
Ok, here is a sample of what my statement looks like:
(The lines marked with ** are the lines in question)
SELECT
Part.PartNum,
Cust.CustNum,
Cust.CustID,
YTD.Qty
FROM
(
SELECT
Pub.Part.PartNum,
Pub.Part.UserChar1 AS CustID
FROM
Pub.Part
) AS Part
LEFT OUTER JOIN (
SELECT
Pub.Customer.CustID,
Pub.Customer.CustNum,
Pub.Customer.Name
FROM
Pub.Customer
WHERE
Pub.Customer.CustID = '1038'
) AS Cust
ON Part.CustID = Cust.CustID
LEFT OUTER JOIN (
SELECT
Pub.OrderDtl.PartNum,
Sum(Pub.OrderDtl.OrderQty) AS Qty
FROM
Pub.OrderHed JOIN Pub.OrderDtl ON
Pub.OrderHed.OrderNum = Pub.OrderDtl.OrderNum
WHERE
**Pub.OrderHed.CustNum = Cust.CustNum AND**
**Pub.OrderDtl.PartNum = Part.PartNum AND**
YEAR(Pub.OrderHed.OrderDate)=YEAR(CURDATE())
GROUP BY
Pub.OrderDtl.PartNum
) AS YTD ON Part.PartNum = YTD.PartNum
Now, I get an error that says:
Part.PartNum cannot be found or is not specified for the query.
I get the same error for Cust.CustNum. Will you help me figure out what I am doing wrong? Thanks!
The problem is that you are using one of the aliases, inside of a sub-query which you cannot do. You will have to do something similar to this:
SELECT Part.PartNum,
Cust.CustNum,
Cust.CustID,
YTD.Qty
FROM
(
SELECT Pub.Part.PartNum,
Pub.Part.UserChar1 AS CustID
FROM Pub.Part
) AS Part
LEFT OUTER JOIN
(
SELECT Pub.Customer.CustID,
Pub.Customer.CustNum,
Pub.Customer.Name
FROM Pub.Customer
WHERE Pub.Customer.CustID = '1038'
) AS Cust
ON Part.CustID = Cust.CustID
LEFT OUTER JOIN
(
SELECT Pub.OrderDtl.PartNum,
Sum(Pub.OrderDtl.OrderQty) AS Qty,
Pub.OrderHed.CustNum
FROM Pub.OrderHed
JOIN Pub.OrderDtl
ON Pub.OrderHed.OrderNum = Pub.OrderDtl.OrderNum
WHERE YEAR(Pub.OrderHed.OrderDate)=YEAR(CURDATE())
GROUP BY Pub.OrderDtl.PartNum, Pub.OrderHed.CustNum
) AS YTD
ON Part.PartNum = YTD.PartNum
AND Cust.CustNum = YTD.CustNum
Looking at your query more, you can actually get rid of two of the subqueries:
SELECT Part.PartNum,
Cust.CustNum,
Cust.CustID,
YTD.Qty
FROM Pub.Part Part
LEFT OUTER JOIN Pub.Customer Cust
ON Part.CustID = Cust.CustID
AND Cust.CustID = '1038'
LEFT OUTER JOIN
(
SELECT d.PartNum,
Sum(d.OrderQty) AS Qty,
h.CustNum
FROM Pub.OrderHed h
JOIN Pub.OrderDtl d
ON h.OrderNum = d.OrderNum
WHERE YEAR(h.OrderDate)=YEAR(CURDATE())
GROUP BY d.PartNum
) AS YTD
ON Part.PartNum = YTD.PartNum
AND Cust.CustNum = YTD.CustNum
This is because you can't access a parent sub-query (cust, part) within another sub-query (YTD)
However, the solution is easy in your case, filter in the ON clause instead:
SELECT
Part.PartNum,
Cust.CustNum,
Cust.CustID,
YTD.Qty
FROM
(
SELECT
Pub.Part.PartNum,
Pub.Part.UserChar1 AS CustID
FROM
Pub.Part
) AS Part
LEFT OUTER JOIN (
SELECT
Pub.Customer.CustID,
Pub.Customer.CustNum,
Pub.Customer.Name
FROM
Pub.Customer
WHERE
Pub.Customer.CustID = '1038'
) AS Cust
ON Part.CustID = Cust.CustID
LEFT OUTER JOIN (
SELECT
Pub.OrderDtl.PartNum,
Sum(Pub.OrderDtl.OrderQty) AS Qty,
Pub.OrderHed.CustNum
FROM
Pub.OrderHed JOIN Pub.OrderDtl ON
Pub.OrderHed.OrderNum = Pub.OrderDtl.OrderNum
WHERE
YEAR(Pub.OrderHed.OrderDate)=YEAR(CURDATE())
GROUP BY
Pub.OrderDtl.PartNum
) AS YTD ON Part.PartNum = YTD.PartNum AND Cust.CustNum = YTD.CustNum