Trying a subquery for my first time and not sure how to within an aggregate statement - sql

I am trying to execute the below script but a, unsure how to combine the aggregate select statement.
I am trying to add the subquery to sum the amount of parts within the fsl. I am getting the following errors:
Msg 8120, Level 16, State 1, Line 17 Column 'Customer.CustInvId' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Msg 8120, Level 16, State 1, Line 16 Column 'dbo.FSLMaster.FSLId' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Can someone please help me be able to execute this? Thank you so much!
P.S.Feel free to tell me I am horrible at explaining and I will do my best to give more details to what I am doing
SELECT c.CustCode
, na.NatName
, c.[Name]
, fm.Code
, fm.FSLName
, cfs.SquareFeet AS 'SQFT'
, CONCAT(a.AddrLine1,',', a.City,',', a.StateAbbr,',', a.ZipCode,',', a.CountryId) AS 'Full Adrress'
, a.AddrLine1
, a.City
, a.StateAbbr
, a.ZipCode
, a.CountryId
, a.Longitude
, a.Latitude
,
(
SELECT ISNULL(SUM(ISNULL(OnHandQty,0) - (ISNULL(ReservedQty,0) )),0) FROM dbo.FSLStock WITH (NOLOCK) WHERE FSLStock.FSLId = FM.FSLId
AND PartMasterId IN ( SELECT PartMasterId FROM dbo.PartMaster P WITH (NOLOCK) WHERE P.CustInvId=C.CustInvId)) AS IOH
FROM Customer C WITH(NOLOCK)
INNER JOIN dbo.CustInvProfile CP WITH(NOLOCK) ON C.CustCode = CP.CustCode AND C.ValidTo IS NULL
INNER JOIN dbo.CustFSLAssociation CF WITH(NOLOCK) ON CF.CustInvId = CP.CustInvId AND CF.ValidTo IS NULL
INNER JOIN dbo.FSLMaster FM WITH(NOLOCK) ON FM.FSLId = CF.FSLId AND (COALESCE(FM.ValidTo,getutcdate()) >= getutcdate())
LEFT JOIN CustFSLStrgDtl CFS WITH(NOLOCK) ON cfs.CustInvId = CF.CustInvId and cfs.FSLId = CF.FSLId
LEFT JOIN [Address] a ON fm.AddrId = a.AddrId
LEFT JOIN NationalAccount na ON c.NatAccountId = na.NatAccountId
LEFT JOIN FSLStock fs ON fm.FSLId = fs.FSLId
GROUP BY c.CustCode, na.NatName, c.[Name], fm.Code, fm.FSLName, cfs.SquareFeet, a.AddrLine1, a.City, a.StateAbbr, a.ZipCode, a.CountryId, a.Longitude, a.Latitude

You can use distinct instead to remove duplicates :
select distinct c.CustCode, na.NatName, c.[Name], fm.Code, fm.FSLName,
. . .
from Customer C inner join
dbo.CustInvProfile CP
on . . .
Note : NOLOCK reads dirty data (uncommitted). Please be aware.

You should be using Group by only when you need some kind of aggregation done at the grouped up levels. You don't actually need the subquery, you can convert it into a join:
SELECT c.CustCode
, na.NatName
, c.[Name]
, fm.Code
, fm.FSLName
, cfs.SquareFeet AS 'SQFT'
, CONCAT(a.AddrLine1,',', a.City,',', a.StateAbbr,',', a.ZipCode,',', a.CountryId) AS 'Full Adrress'
, a.AddrLine1
, a.City
, a.StateAbbr
, a.ZipCode
, a.CountryId
, a.Longitude
, a.Latitude
, SUM(CASE WHEN P.Partmasterid is not null then ISNULL(SUM(ISNULL(OnHandQty,0) - (ISNULL(ReservedQty,0) )),0) else 0 end) as IOH
FROM Customer C WITH(NOLOCK)
INNER JOIN dbo.CustInvProfile CP WITH(NOLOCK) ON C.CustCode = CP.CustCode AND C.ValidTo IS NULL
INNER JOIN dbo.CustFSLAssociation CF WITH(NOLOCK) ON CF.CustInvId = CP.CustInvId AND CF.ValidTo IS NULL
INNER JOIN dbo.FSLMaster FM WITH(NOLOCK) ON FM.FSLId = CF.FSLId AND (COALESCE(FM.ValidTo,getutcdate()) >= getutcdate())
LEFT JOIN CustFSLStrgDtl CFS WITH(NOLOCK) ON cfs.CustInvId = CF.CustInvId and cfs.FSLId = CF.FSLId
LEFT JOIN [Address] a ON fm.AddrId = a.AddrId
LEFT JOIN NationalAccount na ON c.NatAccountId = na.NatAccountId
LEFT JOIN FSLStock fs ON fm.FSLId = fs.FSLId
LEFT JOIN PartMaster P ON P.CustInvId=C.CustInvId
GROUP BY c.CustCode, na.NatName, c.[Name], fm.Code, fm.FSLName, cfs.SquareFeet, a.AddrLine1, a.City,
a.StateAbbr, a.ZipCode, a.CountryId, a.Longitude, a.Latitude
If you think, no aggregation is needed, you can simply remove the group by statement. Hope this helps.

Related

An SQL query with an 'IN' within the where clause is very slow to run

I have created an SQL query which runs but it takes about 17 seconds to complete. I have narrowed down the problem to the IN clause within the Where section of the query. This section is responsible for also finding all records within the same table where the kitref of one record matches the partofkit field of multiple other records.
Could anyone help with suggestions on how I may be able to make this more efficient?
The full SQL is below:
SELECT
tblProductions.ProductionName, tblEquipment.KitRef, tblEquipment.PartOfKit, tblEquipment.Description,
tblCollection.HireID, tblCollection.CollectedBy, Format(tblCollection.DueBack,'dd/MM/yyyy') AS DueBack, Format(tblCollection.CollectionDate,'dd/MM/yyyy') AS CollectionDate, Format(tblCollection.CollectionTime,'HH:mm') AS CollectionTime, tblCollection.DiscountPC,
tblCollectionItemized.HireLine, tblCollectionItemized.Notes, tblCollectionItemized.BookingActive, tblCollectionItemized.DepositReturned, tblTariff.Tariff
FROM tblTariff
INNER JOIN (
tblProductions INNER JOIN (
tblCollection INNER JOIN (
tblEquipment
INNER JOIN tblCollectionItemized ON tblEquipment.KitKey = tblCollectionItemized.KitKey
) ON tblCollection.HireID = tblCollectionItemized.HireID)
ON tblProductions.ProductionIDKey = tblCollection.ProductionName
) ON tblTariff.TariffKey = tblCollection.Tarriff
WHERE (
tblCollectionItemized.BookingActive='TRUE'
AND tblEquipment.PartOfKit IN (
SELECT tblEquipment.KitRef
FROM tblEquipment
INNER JOIN tblCollectionItemized ON tblEquipment.KitKey = tblCollectionItemized.KitKey
WHERE tblCollectionItemized.ReturnsNumber =43
)
)
OR (
tblCollectionItemized.BookingActive='TRUE'
AND tblCollectionItemized.ReturnsNumber =43
)
Not a complete answer here but using some aliases and joins in a logical order make this nightmarish query into something a lot easier to see what is going on.
SELECT
p.ProductionName
, e.KitRef
, e.PartOfKit
, e.Description
, c.HireID
, c.CollectedBy
, Format(c.DueBack,'dd/MM/yyyy') AS DueBack
, Format(c.CollectionDate,'dd/MM/yyyy') AS CollectionDate
, Format(c.CollectionTime,'HH:mm') AS CollectionTime
, c.DiscountPC
, ci.HireLine
, ci.Notes
, ci.BookingActive
, ci.DepositReturned
, t.Tariff
FROM tblTariff t
INNER JOIN tblCollection c ON t.TariffKey = c.Tarriff
INNER JOIN tblProductions p ON p.ProductionIDKey = c.ProductionName
INNER JOIN tblCollectionItemized ci ON c.HireID = ci.HireID
INNER JOIN tblEquipment e ON e.KitKey = ci.KitKey
WHERE ci.BookingActive = 'TRUE'
AND e.PartOfKit IN
(
SELECT e2.KitRef
FROM tblEquipment e2
INNER JOIN tblCollectionItemized ci2 ON e2.KitKey = ci2.KitKey
WHERE ci2.ReturnsNumber = 43
)
OR
(
ci.ReturnsNumber = 43
)
you can try EXISTS instead of IN and add (nolock) hint to tables
SELECT
P.ProductionName,
E.KitRef,
E.PartOfKit,
E.Description,
C.HireID,
C.CollectedBy,
Format(C.DueBack,'dd/MM/yyyy') AS DueBack,
Format(C.CollectionDate,'dd/MM/yyyy') AS CollectionDate,
Format(C.CollectionTime,'HH:mm') AS CollectionTime,
C.DiscountPC,
CI.HireLine,
CI.Notes,
CI.BookingActive,
CI.DepositReturned,
T.Tariff
FROM tblTariff T
INNER JOIN tblCollection C (nolock) ON T.TariffKey = C.Tarriff
INNER JOIN tblProductions P (nolock) ON P.ProductionIDKey = C.ProductionName
INNER JOIN tblCollectionItemized CI (nolock) ON C.HireID = CI.HireID
INNER JOIN tblEquipment E (nolock) ON E.KitKey = CI.KitKey
WHERE (
tblCollectionItemized.BookingActive='TRUE'
AND EXISTS (
SELECT *
FROM tblEquipment E2 (nolock)
INNER JOIN tblCollectionItemized CI2 (nolock) ON E2.KitKey = CI2.KitKey
WHERE CI2.ReturnsNumber =43 AND E.PartOfKit = E2.KitRef )
)
OR (
CI.BookingActive='TRUE'
AND CI.ReturnsNumber =43
)

Applying cluster indexing to a view in SQL Server 2012

I have a view which queries around 1+ million rows and takes around 10-15 minutes to finish its execution,I want to provide cluster indexing to it so that it exists in physical schema and takes less time to load, but there are a number of constraints in order to provide cluster indexing i.e. only INNER JOIN are allowed and No subqueries should be present in views defination how do I replace the LEFT JOIN present in this view with INNER JOIN and how do I eliminate subqueries from this views defination so that cluster indexing can be applied to it.
CREATE view [dbo].[FTM_ProfileDetailsView] with SCHEMABINDING as
select FTM.Id
, FTM.EmployeeId
, FTM.CustomerId
, FTM.AbsenceFirstDate
, FTM.BackgroundHistory
, FTM.BackgroundHistoryComments
, FTM.IsEmployeeAbsent,FTM.ServiceId
, Case When isnull(FTM.IsSelfManagement,'')='' THEN cast(0 as bit) ELSE FTM.IsSelfManagement END as IsSelfManagement
, PR.ServiceLineId,FTM.ProfileId,PR.StatusId,Status.Status as StatusName
, PR.ReasonID
, PR.ModifiedDate
, PR.WithdrawnReason
, PR.CreatedBy
, PR.CreatedDate
, PR.IsActive
, mgrs.usernames as LineManagers
, cust.CustomerName
, ltrim(rtrim( emp.EmployeeTitle+' '+ emp.FirstName+' '+ emp.Surname)) as EmployeeFullName
, FTM.ProfileManagerId
, FTM.IsProfileManagement
, AM.MonitoringChecks
, AM.Frequency
, AM.ProfileManagerNotes
, AM.TaskDateAndTime
, FTM.ProfileManagementCriteriaId
,cast(case when PR.StatusId = 13 then 1 else 0 end as bit) as IsActiveMonitoring
, CustServ.CustomerServiceName
, BU.Name as BusinessUnit
, emp.DASID
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
, (select top 1
StatusId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc) as LatestInterventionStatusId
, (select name from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc))
as LatestInterventionName from FTM_Profile FTM
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
INNER JOIN dbo.PR_Profile PR on PR.Profileid=FTM.ProfileId
LEFT JOIN dbo.BusinessUnit BU on BU.Id=PR.BUId
LEFT JOIN dbo.PR_dv_Status [Status] on [Status].Id = PR.StatusId
LEFT JOIN dbo.CM_ActiveMonitoringDetails AM on AM.ProfileId = PR.Profileid
LEFT JOIN dbo.FTM_CustomerServiceMapping CustServ on CustServ.ServiceId = FTM.ServiceId and CustServ.CustomerId = FTM.CustomerId
LEFT JOIN dbo.contact con on con.Id = emp.ContactID
LEFT JOIN dbo.address addr on addr.Id = con.HomeAddressId
LEFT JOIN dbo.contactinfo coninfo on coninfo.Id = con.ContactInfoId
I have a suggestion. Can you try and change your query so the sub -queries in the SELECT are placed in CROSS APPLYs?
So something along the lines of this in your WHERE clause:
CROSS APPLY (
select top 1 StatusId AS LatestInterventionStatusId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc
) LatestInterventionStatusId
CROSS APPLY (
select name AS LatestInterventionName
from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc)
)LatestInterventionName
And then of course change the column names in the SELECT to something like this:
, LatestInterventionStatusId.LatestInterventionStatusId
, LatestInterventionName.LatestInterventionName
Give this a go and let me know if it makes a different.
Ok, you didn't give me an answer on my question, but the subqueries should be changed. Try to use this instead the two subqueries:
/*
...
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
*/
, p.StatusId as LatestInterventionStatusId
, p.name as LatestInterventionName
from FTM_Profile FTM
OUTER APPLY (
select TOP 1 Intr.name, ProfileInt.StatusId
from dbo.PR_Profileintervention ProfileInt
LEFT JOIN dbo.FTM_Intervention Intr ON Intr.Id = ProfileInt.InterventionId
where ProfileInt.ProfileId = FTM.Profileid
order by ProfileInt.Id desc
) p
/*
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
...
*/

SQL Left Outer Join acting like Inner Join

I am trying to do a left outer join on two tables (well, an inline view and a table).
What I want to happen is to list all the grads (I know there are 3815 DISTINCT Grads) with any of their enrolments (there could be 0 or n enrolments). What I'm getting is only a list of the grads that have enrolments (3649 DISTINCT students). I'm not sure where I'm going wrong with not getting all the rows from the grad 'view' (I don't have create view privs so this is my workaround).
This is my code:
SELECT C.*, D.FREEZE_EVENT, D.ACADEMIC_PERIOD, D.CAMPUS, D.COLLEGE, D.COLLEGE_DESC,D.MAJOR, D.MAJOR_DESC , D.STUDENT_RATE
FROM
(SELECT A.STUDENT_LEVEL_DESC, A.CAMPUS, A.CAMPUS_DESC, A.COLLEGE, A.COLLEGE_DESC, A.MAJOR_DESC, A.MAJOR, A.DEGREE_DESC, A.PERSON_UID, A.ID, A.NAME,
A.OUTCOME_GRADUATION_DATE, A.STATUS, A.GRAD_YEAR, A.TRAINING_LOCATION, B.CITIZENSHIP_TYPE
FROM ACAD_OUTOCME A, PERSON_DETAIL B
WHERE A.STUDENT_LEVEL IN ('02','03') AND A.GRAD_YEAR = '2015' AND A.FREEZE_EVENT = '10TH_SEP2016' AND B.FREEZE_EVENT = '10TH_SEP2016'
AND A.ID = B.ID) C
LEFT OUTER JOIN ACAD_STUDY D ON
C.CAMPUS = D.CAMPUS
AND C.COLLEGE = D.COLLEGE
AND C.MAJOR = D.MAJOR
AND C.PERSON_UID = D.PERSON_UID
WHERE D.FREEZE_EVENT = '10TH_SEP2016'
ORDER BY C.NAME
Any suggestions? I'm using Toad Data Point. I'm also the loan developer at work, so I don't have anyone I can ask to help out with this, and google has failed me.
Thanks!
Move your WHERE condition to the ON condition:
Select C.*
, D.FREEZE_EVENT
, D.ACADEMIC_PERIOD
, D.CAMPUS
, D.COLLEGE
, D.COLLEGE_DESC
, D.MAJOR
, D.MAJOR_DESC
, D.STUDENT_RATE
From (Select A.STUDENT_LEVEL_DESC
, A.CAMPUS
, A.CAMPUS_DESC
, A.COLLEGE
, A.COLLEGE_DESC
, A.MAJOR_DESC
, A.MAJOR
, A.DEGREE_DESC
, A.PERSON_UID
, A.ID
, A.NAME
, A.OUTCOME_GRADUATION_DATE
, A.STATUS
, A.GRAD_YEAR
, A.TRAINING_LOCATION
, B.CITIZENSHIP_TYPE
From ACAD_OUTOCME A
Join PERSON_DETAIL B On A.ID = B.ID
Where A.STUDENT_LEVEL In ('02', '03')
And A.GRAD_YEAR = '2015'
And A.FREEZE_EVENT = '10TH_SEP2016'
And B.FREEZE_EVENT = '10TH_SEP2016'
) C
Left Outer Join ACAD_STUDY D
On C.CAMPUS = D.CAMPUS
And C.COLLEGE = D.COLLEGE
And C.MAJOR = D.MAJOR
And C.PERSON_UID = D.PERSON_UID
And D.FREEZE_EVENT = '10TH_SEP2016'
Order By C.NAME;
The WHERE clause is evaluated after the OUTER JOIN, which would cause it to filter out the NULL records from the LEFT JOIN. So, having the right-hand table of a LEFT JOIN in the WHERE clause will effectively transform the OUTER JOIN into an INNER JOIN.

Using a group by to group a select statement

Using a group by to group a select stament
SELECT
k.Ivalue, k.JOBDESCRIPTION ,
count( k.Ivalue) as TOTAL
FROM
(SELECT
a."ID" as Ivalue, b."JOBDESCRIPTION", rq."CURRENTSTATUS"
FROM
tblG2o_Requests a
INNER JOIN
tblG2o_JOBS b ON a."JOBPOSTID" = b."ID"
INNER JOIN
(SELECT
r.REQUESTID, ir."CURRENTSTATUS"
FROM
TBLG2O_RESULTSPOOL r
INNER JOIN
tblG2o_Requests ir ON r.RequestID = ir."ID"
WHERE
r.ShortListed = '1') rq ON rq.REQUESTID = a."ID"
WHERE
"ACTIVE" = '1'
AND "DATECOMPLETED" IS NULL
ORDER BY
"REQUESTDATE" DESC) k
GROUP BY
k.JOBDESCRIPTION
What is the question? You seem to be missing the group by clause, and you do not need double quotes around field names unless you have spaces in them, and even then, if TSQL for example, you would use [] in preference.
I had to remove an ORDER BY in the subquery, that isn't allowed unless other conditions demand it (like TOP n in TSQL)
SELECT
k.Ivalue
, k.JOBDESCRIPTION
, COUNT(k.Ivalue) AS TOTAL
FROM (
SELECT
a.ID AS Ivalue
, b.JOBDESCRIPTION
, rq.CURRENTSTATUS
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a.JOBPOSTID = b.ID
INNER JOIN (
SELECT
r.REQUESTID
, ir.CURRENTSTATUS
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r.RequestID = ir.ID
WHERE r.ShortListed = '1'
) rqenter
ON rq.REQUESTID = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
) k
GROUP BY
k.Ivalue
, k.JOBDESCRIPTION
Finally worked
SELECT
k.Ivalue
, l.JOBDESCRIPTION
, k.TOTAL,
k.CURRENTSTATUS
FROM (
SELECT
a.ID AS Ivalue
,b.ID as JobPostID
, rq."CURRENTSTATUS"
,COUNT(a.ID) AS TOTAL
FROM tblG2o_Requests a
INNER JOIN tblG2o_JOBS b
ON a."JOBPOSTID" = b.ID
INNER JOIN (
SELECT
r."REQUESTID"
, ir."CURRENTSTATUS"
FROM TBLG2O_RESULTSPOOL r
INNER JOIN tblG2o_Requests ir
ON r."REQUESTID" = ir.ID
WHERE r."SHORTLISTED" = 1
) rq
ON rq."REQUESTID" = a.ID
WHERE ACTIVE = '1'
AND DATECOMPLETED IS NULL
GROUP BY
a.ID ,b.ID
, rq."CURRENTSTATUS" ) k
inner join tblG2o_JOBS l on k.JobPostID =l.ID
enter code here

Newbie - incorrect syntax error near the word where

SELECT
o.id, o.Name, o.StageName, o.[Type], o.Account__c, o.SalesPerson__c,
o2.AccountId__c,o2.Sales_Person__c, o2.InvoiceDate__c
FROM customers.dbo.sales as o
INNER JOIN customers.dbo.account as a on a.Id = o.AccountId
INNER JOIN
(
Select MAX(Id)Id, AccountId
FROM customers.dbo.order__c
WHERE Sales_Person__c <> NULL
) as o1
INNER JOIN Customers.dbo.Order__c as o2 on o2.Id = o1.Id
WHERE (o.SalesPerson__c = NULL)
AND (o.[Type] = 'Renewal')
AND (o.StageName NOT LIKE 'Closed%')
Not sure what I did wrong. I'm getting the following error:
Incorrect syntax near the keyword 'Where'
I'm trying to get the most recent Order for each account. Any help would be greatly appreciated.
Your issue is the <> NULL and the = NULL, you need to use IS NULL or IS NOT NULL. Depending on your RDBMS you also need a GROUP BY in your subquery with the MAX():
select o.id
, o.Name
, o.StageName
, o.[Type]
, o.Account__c
,o.SalesPerson__c
, o2.AccountId__c
, o2.Sales_Person__c
, o2.InvoiceDate__c
from customers.dbo.sales as o
Inner Join customers.dbo.account as a
on a.Id = o.AccountId
INNER JOIN
(
Select MAX(Id)Id, AccountId
from customers.dbo.order__c
where Sales_Person__c IS NOT NULL
GROUP BY AccountId -- depending on the RDBMS you need a GROUP BY
) o1
INNER JOIN Customers.dbo.Order__c o2
on o2.Id = o1.Id
Where (o.SalesPerson__c IS NULL)
and (o.[Type] = 'Renewal')
and (o.StageName NOT LIKE 'Closed%')
Your Inner Join called o1 doesn't join on anything. I'm not sure exactly what you are trying to do, but I think if you remove the inner join for o1, and instead have that as an exists in your where clause, it might work better. You also have to change your o2 join to join on o2.AccountId = a.Id, which I think is what you are trying to do.
select o.id
, o.Name
, o.StageName
, o.[Type]
, o.Account__c
, o.SalesPerson__c
, o2.AccountId__c
, o2.Sales_Person__c
, o2.InvoiceDate__c
from customers.dbo.sales as o
Inner Join customers.dbo.account as a
on a.Id = o.AccountId
INNER JOIN Customers.dbo.Order__c as o2
on o2.AccountId = a.Id
Where (o.SalesPerson__c is NULL)
and (o.[Type] = 'Renewal')
and (o.StageName NOT LIKE 'Closed%')
and exists(
Select MAX(Id) as id
from customers.dbo.order__c c
where c.Sales_Person__c is not NULL
and id = o2.id)