Sub sum query bringing back more results then possible - sql

I am currently running the following query.( See below) However when I run this query the active users and Suspended users are bring back a far greater result then that's in the database.
I just wondered if you could possibly shed light on the reason why and correct me where I'm going wrong?
SELECT c.[Status],
c.CompanyId,
c.Name,
(SELECT count(DISTINCT usr.UserID)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = c.CompanyID) AS TotalUsers,
(SELECT sum (CASE
WHEN usr.Status = 2 THEN 1
ELSE 0
END)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = c.CompanyID) AS ActiveUsers,
(SELECT sum (CASE
WHEN usr.Status = 3 THEN 1
ELSE 0
END)
FROM [ondemand.10cms.com].Security.[User] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = c.CompanyID) AS SuspendedUsers
FROM [ondemand.10cms.com].Company.Company c

In each of your sub queries you have two tables, one is being joined to the outer query but there is no join between the two inner tables. All of those sub queries are a bit unnecessary, I would rewrite as a simpler query, something like so:
SELECT
Company.[Status]
,Company.CompanyId
,Company.Name
,COUNT(DISTINCT usr.UserID) AS TotalUsers
,SUM(CASE WHEN usr.Status = 2 THEN 1
ELSE 0
END) AS ActiveUsers
,SUM(CASE WHEN usr.Status = 3 THEN 1
ELSE 0
END) AS SuspendedUsers
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
GROUP BY
Company.[Status]
,Company.CompanyId
,Company.Name
If you just wabt a fix for your query as is then try this:
SELECT c.[Status],
c.CompanyId,
c.Name,
(SELECT count(DISTINCT usr.UserID)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
WHERE usr.CompanyID = c.CompanyID) AS TotalUsers,
(SELECT sum (CASE
WHEN usr.Status = 2 THEN 1
ELSE 0
END)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
WHERE usr.CompanyID = c.CompanyID) AS ActiveUsers,
(SELECT sum (CASE
WHEN usr.Status = 3 THEN 1
ELSE 0
END)
FROM [ondemand.10cms.com].Security.[User] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
WHERE usr.CompanyID = c.CompanyID) AS SuspendedUsers
FROM [ondemand.10cms.com].Company.Company c

I don't know your data (it could cause duplicates), but couldnt you use a standard group by and not use sub queries?
Select
c.[Status],
c.CompanyId,
c.Name,
count(distinct usr.UserID) as TotalUsers,
sum(case when usr.Status = 2 then 1 else 0 end) as ActiveUsers,
sum(case when usr.Status = 3 then 1 else 0 end) as SuspendedUsers
from [ondemand.10cms.com].Company.Company c
inner join [ondemand.10cms.com].Security.[user] usr
on usr.CompanyID=c.CompanyID
GROUP BY
c.[Status],
c.CompanyId,
c.Name

Try adding a group by CompanyId and let us know how that worked.

Related

Joining two queries to one table and substracting values

i need to put those two output values (Add_sum and Minus_sum) to one table and subtract them (Add_sum - Minus_sum) and show this value.
I tried many other options, subqueries etc but could not get it to work.
Query 1:
SELECT I.ItemCode, COUNT(H.TransactionTypeID) AS ADD_Sum
FROM inMoveHd AS H INNER JOIN
inMoveLn AS L ON L.InvMoveID = H.InvMoveID INNER JOIN
inItem AS I ON I.ItemID = L.ItemID INNER JOIN
inTransactionType AS T ON H.TransactionTypeID = T.TransactionTypeID
WHERE (T.TransactionSign = 1)
GROUP BY I.ItemCode
Query 2:
SELECT I.ItemCode, COUNT(H.TransactionTypeID) AS Minus_Sum
FROM inMoveHd AS H INNER JOIN
inMoveLn AS L ON L.InvMoveID = H.InvMoveID INNER JOIN
inItem AS I ON I.ItemID = L.ItemID INNER JOIN
inTransactionType AS T ON H.TransactionTypeID = T.TransactionTypeID
WHERE (T.TransactionSign = -1)
GROUP BY I.ItemCode
Use case expressions to do conditional aggregation:
SELECT I.ItemCode,
COUNT(case when T.TransactionSign = 1 then H.TransactionTypeID end) AS ADD_Sum,
COUNT(case when T.TransactionSign = -1 then H.TransactionTypeID end) AS Minus_Sum
FROM inMoveHd AS H INNER JOIN
inMoveLn AS L ON L.InvMoveID = H.InvMoveID INNER JOIN
inItem AS I ON I.ItemID = L.ItemID INNER JOIN
inTransactionType AS T ON H.TransactionTypeID = T.TransactionTypeID
WHERE (T.TransactionSign = -1 or T.TransactionSign = 1)
GROUP BY I.ItemCode
I think that you are looking for conditional aggregation:
SELECT
I.ItemCode,
SUM(CASE WHEN T.TransactionSign = 1 THEN 1 ELSE 0 END) AS Add_Sum,
SUM(CASE WHEN T.TransactionSign = -1 THEN 1 ELSE 0 END) AS Minus_Sum,
SUM(T.TransactionSign) difference
FROM
inMoveHd AS H INNER JOIN
inMoveLn AS L ON L.InvMoveID = H.InvMoveID INNER JOIN
inItem AS I ON I.ItemID = L.ItemID INNER JOIN
inTransactionType AS T ON H.TransactionTypeID = T.TransactionTypeID
WHERE T.TransactionSign IN (-1, 1)
GROUP BY I.ItemCode

SQL Server 2012 - is there a better way to do this as when there are duplicates it counts them more than once?

This is not accurate as the count can be wrong so is there a better way using exists? I want to identify if one case of each course exists.
SELECT
IdentityCourses.IdentityID AS ID,Identities.LastName AS LastName,
Identities.FirstNames AS FirstName,Units.UnitID, Units.Description AS Unit
FROM
dbo.UnitIdentities
INNER JOIN
dbo.IdentityCourses ON dbo.UnitIdentities.IdentityID = dbo.IdentityCourses.IdentityID
INNER JOIN
dbo.COCSourceCourses ON dbo.IdentityCourses.CourseID = dbo.COCSourceCourses.CBESCourseID
INNER JOIN
dbo.Identities ON dbo.UnitIdentities.IdentityID = dbo.Identities.IdentityID
INNER JOIN
dbo.Units ON dbo.UnitIdentities.UnitID = dbo.Units.UnitID
WHERE
(dbo.UnitIdentities.IsActiveMember = 1)
GROUP BY
IdentityCourses.IdentityID, Identities.LastName, Identities.FirstNames,
Units.Description, Units.UnitID
HAVING
(SUM((CASE WHEN COCSourceCourses.COCID = 10048 then 1 else 0 end)+
(CASE WHEN COCSourceCourses.COCID = 10049 then 1 else 0 end)+
(CASE WHEN COCSourceCourses.COCID = 10050 then 1 else 0 end)+
(CASE WHEN COCSourceCourses.COCID = 10051 then 1 else 0 end)+
(CASE WHEN COCSourceCourses.COCID = 10063 then 1 else 0 end)+
(CASE WHEN COCSourceCourses.COCID = 10073 then 1 else 0 end))) = 6
AND IdentityCourses.IdentityID NOT IN (SELECT IdentityID
FROM IdentityQualifications
WHERE QualificationID IN (1012, 1014, 1025))
ORDER BY
Units.UnitID
Try using count(distinct ..):
SELECT (..columns..)
FROM dbo.UnitIdentities UI
LEFT JOIN IdentityQualifications IQ
ON IQ.IdentityID = UI.IdentityID
AND IQ.QualificationID IN (1012, 1014, 1025)
INNER JOIN dbo.IdentityCourses IC
ON IC.IdentityID = dbo.UnitIdentities.IdentityID
INNER JOIN dbo.COCSourceCourses COC
ON COC.CBESCourseID = IC.CourseID
AND COC.COCID IN (10048, 10049, 10050, 10051, 10063, 10073)
(..two more table joins on identities and units..)
WHERE IQ.IdentityID IS NULL
GROUP BY (..columns..)
HAVING COUNT(DISTINCT COC.COCID) = 6
ORDER BY Units.UnitID
When you are only interested in certain records, then why don't you use the WHERE clause? Only select the COCIDs you are interested in and then count distinct results.
You don't need any GROUP BY and HAVING by the way, as you only display identities/units, so you can count associated courses in a subquery in your WHERE clause.
select
i.identityid as id,
i.lastname as lastname,
i.firstnames as firstname,
u.unitid,
u.description as unit
from dbo.identities i
join dbo.unitidentities ui on ui.identityid = i.identityid and ui.isactivemember = 1
join dbo.units u on u.unitid = ui.unitid
where i.identityid not in
(
select iq.identityid
from identityqualifications iq
where iq.qualificationid in (1012, 1014, 1025)
)
and
(
select count(distinct sc.cocid)
from dbo.cocsourcecourses sc
join dbo.identitycourses ic on ic.courseid = sc.cbescourseid
where sc.cocid in (10048, 10049, 10050, 10051, 10063, 10073)
and ic.identityid = i.identityid
) = 6
order by u.unitid;

How to use group by in SQL Server

Query:
SELECT
dbo.tblDivision.DivisionName, dbo.tblDistrict.DistrictName,
case
when Gender = 'Male'
then count(Gender)
end as male,
case
when Gender = 'female'
then count(Gender)
end as female,
UnitEName
FROM
dbo.tblDistrict
INNER JOIN
dbo.tblThana ON dbo.tblDistrict.DistrictNo = dbo.tblThana.DistrictNo
INNER JOIN
dbo.tblDivision ON dbo.tblDistrict.DivisionNo = dbo.tblDivision.DivisionNo
INNER JOIN
dbo.vw_EmpInfo ON dbo.tblThana.ThanaNo = dbo.vw_EmpInfo.PerThanaNo
GROUP BY
Gender, DistrictName, DivisionName, UnitEName, UnitEAddress
ORDER BY
DivisionName, DistrictName, UnitEName
This results like below:
but I want every unit's result in one single row. may be I have problem in my group by.
How should I refactor my query?
If you want both genders in one row, you should not group by gender.
Instead you should add up how many male and how many female there are using sum():
SELECT dbo.tblDivision.DivisionName, dbo.tblDistrict.DistrictName,
SUM(case when Gender='Male' then 1 else 0 end) as male,
SUM(case when Gender='Female' then 1 else 0 end) as female,
UnitEName
FROM dbo.tblDistrict INNER JOIN
dbo.tblThana ON dbo.tblDistrict.DistrictNo = dbo.tblThana.DistrictNo INNER JOIN
dbo.tblDivision ON dbo.tblDistrict.DivisionNo = dbo.tblDivision.DivisionNo INNER JOIN
dbo.vw_EmpInfo ON dbo.tblThana.ThanaNo = dbo.vw_EmpInfo.PerThanaNo
group by DistrictName,DivisionName,UnitEName,UnitEAddress
order by DivisionName,DistrictName,UnitEName
You have to leave Gender column out of the grouping clause:
SELECT dbo.tblDivision.DivisionName, dbo.tblDistrict.DistrictName,
COUNT(CASE Gender WHEN 'Male' THEN 1 END) AS male,
COUNT(CASE Gender WHEN 'female' THEN 1 END) AS female,
UnitEName
FROM dbo.tblDistrict
INNER JOIN dbo.tblThana ON dbo.tblDistrict.DistrictNo = dbo.tblThana.DistrictNo
INNER JOIN dbo.tblDivision ON dbo.tblDistrict.DivisionNo = dbo.tblDivision.DivisionNo
INNER JOIN dbo.vw_EmpInfo ON dbo.tblThana.ThanaNo = dbo.vw_EmpInfo.PerThanaNo
GROUP BY DistrictName,DivisionName,UnitEName,UnitEAddress
ORDER BY DivisionName,DistrictName,UnitEName
SELECT dbo.tblDivision.DivisionName
, dbo.tblDistrict.DistrictName
,COUNT(case when Gender='Male' then 1 end) as male
,COUNT(case when Gender='female' then 1 end) as female
,UnitEName
FROM dbo.tblDistrict
INNER JOIN dbo.tblThana ON dbo.tblDistrict.DistrictNo = dbo.tblThana.DistrictNo
INNER JOIN dbo.tblDivision ON dbo.tblDistrict.DivisionNo = dbo.tblDivision.DivisionNo
INNER JOIN dbo.vw_EmpInfo ON dbo.tblThana.ThanaNo = dbo.vw_EmpInfo.PerThanaNo
GROUP BY DivisionName
,DistrictName
,UnitEName
Remove Gender from Group by clause
SELECT dbo.tblDivision.DivisionName, dbo.tblDistrict.DistrictName,
sum (case when Gender='Male' then 1 else 0 end) as male
sum (case when Gender='female' then 1 else 0 end) as female,
UnitEName
FROM dbo.tblDistrict
INNER JOIN dbo.tblThana ON dbo.tblDistrict.DistrictNo = dbo.tblThana.DistrictNo
INNER JOIN dbo.tblDivision ON dbo.tblDistrict.DivisionNo = dbo.tblDivision.DivisionNo
INNER JOIN dbo.vw_EmpInfo ON dbo.tblThana.ThanaNo = dbo.vw_EmpInfo.PerThanaNo
GROUP BY DistrictName,DivisionName,UnitEName,UnitEAddress
ORDER BY DivisionName,DistrictName,UnitEName

Same values being returned for multiple rows in sql but not all columns

i'm currently running the following query (see below.)
However when i do the same values is returned for multiple rows in totalusers, activeusers and suspendedusers.
However when it comes to total login the values are unique.
Is their a reason why this could be happening and is their a way to solve the problem. If it helps im using the tool sql workben with postgre sql driver.
Cheers
SELECT
company.companyStatus,
company.CompanyId,
company.companyName,
select
count(distinct UserID)
From Users
inner join company
on Users.CompanyID = Company.CompanyId
where Users.Companyid = company.Companyid
as TotalUsers,
select sum(case when userstatusid =2 then 1 else 0 end)
from users
inner join company
on users.companyid = company.companyid
where users.companyid = company.companyid)
as ActiveUsers,
select sum(case when userstatusid = 3 then 1 else 0 end)
from users
inner join company
on users.companyid = company.companyid
where users.companyid = company.companyid)
as SuspendedUsers,
(Select COUNT (distinct usersessionid)
From UserSession
inner join users
on usersession.UserID=users.UserID
where usersession.UserID=users.UserID
and users.companyid= company.CompanyID)
as TotalLogin,
from Company
Its because your TotalUsers, ActiveUsers and SuspendedUsers queries are all using their own (unrestricted) copy of the Company table, whereas your TotalLogin is using the main instance from which you're selecting. This means that the TotalLogin numbers you're seeing are for that particular company, but the other fields are across ALL companies.
Presumably you wanted something more like:
SELECT
company.companyStatus,
company.CompanyId,
company.companyName,
count(distinct u.UserID) TotalUsers,
sum(case when u.userstatusid =2 then 1 else 0 end) ActiveUsers,
sum(case when u.userstatusid = 3 then 1 else 0 end) SuspendedUsers,
count(distinct u.usersessionid) TotalLogin
from Company
inner join Users on Users.CompanyID = Company.CompanyId
The reason is because you have company in the subqueries for those calculations.
I much prefer having table references in the from clause where possible, and you can write this query moving everything to the from clause:
SELECT c.companyStatus, c.CompanyId, c.companyName,
uc.Totalusers, uc.Activeusers, uc.Suspendedusers, ucs.TotalLogin
from Company c left outer join
(select u.companyid,
COUNT(distinct userid) as Totalusers,
SUM(case when userstatusid = 2 then 1 else 0 end) as ActiveUsers,
sum(case when userstatusid = 3 then 1 else 0 end) as Suspendedusers
from users u
group by u.companyid
) uc
uc.companyid = c.companyId left outer join
(select u.companyid, COUNT(distinct usersessionid) as TotalLogin
from UserSession us inner join
users u
on us.UserID = u.UserID
) ucs
on ucs.companyid = c.companyid;
This should also speed up the query because it doesn't have to do the same work multiple times.

How to link sql sub queries together?

is it possible to link the following sub query (see below.) The first three sub queries work fine however I'm struggling to see how to do the rest any guidance would be great cheers.
Ps. apologies for the long code
SELECT c.[Status],
c.CompanyId,
c.Name,
(SELECT count(DISTINCT usr.UserID)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
WHERE usr.CompanyID = c.CompanyID) AS TotalUsers,
(SELECT sum (CASE WHEN usr.Status = 2 THEN 1 ELSE 0 END)
FROM [ondemand.10cms.com].Security.[user] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID
WHERE usr.CompanyID = c.CompanyID) AS ActiveUsers,
(SELECT sum (CASE WHEN usr.Status = 3 THEN 1 ELSE 0 END)
FROM [ondemand.10cms.com].Security.[User] usr
INNER JOIN [ondemand.10cms.com].Company.Company
ON usr.CompanyID = Company.CompanyID WHERE usr.CompanyID = c.CompanyID) AS SuspendedUsers,
(Select COUNT (distinct usrs.id)
From [ondemand.10cms.com].Security.UserSession usrs
inner join [ondemand.10cms.com].Security.[user] usr on usrs.UserID=usr.UserID
) as TotalLogin,
(Select
COUNT( MerchandisingModule.Name)
From [ondemand.10cms.com].Project.Template
inner join [ondemand.10cms.com].Project.MerchandisingModule on Template.TemplateID= MerchandisingModule.TemplateId
)as CurrentModules,
(Select
count(MerchandisingModule.CreatedDate)
from [ondemand.10cms.com].Project.MerchandisingModule
inner join [ondemand.10cms.com].Project.Template on Template.TemplateID= MerchandisingModule.TemplateId
)as ModulesCreated,
(Select
count(mm.UpdatedDate)
from [ondemand.10cms.com].Project.MerchandisingModule mm
inner join [ondemand.10cms.com].Project.Template on Template.TemplateID= mm.TemplateId
)as ModulesUpdated,
(Select
COUNT(MA.MerchandisingAreaID)
from [ondemand.10cms.com].Project.MerchandisingArea MA
inner join [ondemand.10cms.com].Project.Project on Project.ProjectID= MA.ProjectID
) as Currentareas,
(Select
COUNT (MA.name)
from [ondemand.10cms.com].Project.MerchandisingArea MA
inner join [ondemand.10cms.com].Project.Project on Project.ProjectID= MA.ProjectID
) as AreasCreated,
(select
COUNT (MerchandisingArea.UpdatedDate)
from [ondemand.10cms.com].Project.MerchandisingArea
inner join [ondemand.10cms.com].Project.Project on Project.ProjectID= MerchandisingArea.ProjectID
) as AreasUpdated,
(Select
SUM ( case when MA.PublishStatus = 1 then 1 else 0 end)
from [ondemand.10cms.com].Project.MerchandisingArea MA
inner join [ondemand.10cms.com].Project.PublishingStatus on PublishingStatus.PublishStatusId = MA.PublishStatus
) as SuccessPublished,
(Select
SUM ( case when MA.PublishStatus = 3 then 1 else 0 end)
from [ondemand.10cms.com].Project.MerchandisingArea MA
inner join [ondemand.10cms.com].Project.PublishingStatus on PublishingStatus.PublishStatusId= MA.PublishStatus
) as FailedPublished
from [ondemand.10cms.com].Company.Company c
This was fixed by adding another inner join to each sub query and also another where clause