Sql: Select count(*) from (select ...) - sql

I have a sql select command with grouping and I want to get the number of total rows. How do I achieve that?
My sql command:
select p.UserName, p.FirstName + ' ' + p.LastName as [FullName]
,count(b.billid) as [Count], sum(b.PercentRials) as [Sum] from Bills b
inner join UserProfiles p on b.PayerUserName=p.UserName
where b.Successful=1
group by p.UserName, p.FirstName + ' ' + p.LastName
I have tried these with no luck:
select count(*) from (select ...)
and
select count(select ...)
EDIT
this is the complete sql statement that I want to run:
select count(*) from ( select p.UserName, p.FirstName + ' ' + p.LastName as [FullName]
,count(b.billid) as [Count], sum(b.PercentRials) as [Sum] from Bills b
inner join UserProfiles p on b.PayerUserName=p.UserName
where b.Successful=1
group by p.UserName, p.FirstName + ' ' + p.LastName)
and I get this error on the last line:
Incorrect syntax near ')'.

SELECT COUNT(*)
FROM
(
select p.UserName, p.FirstName + ' ' + p.LastName as [FullName]
,count(b.billid) as [Count], sum(b.PercentRials) as [Sum] from Bills b
inner join UserProfiles p on b.PayerUserName=p.UserName
where b.Successful=1
group by p.UserName, p.FirstName + ' ' + p.LastName --<-- Removed the extra comma here
) A --<-- Use an Alias here
As I expected from your shown attempt you were missing an Alias
select count(*)
from (select ...) Q --<-- This sub-query in From clause needs an Alias
Edit
If you only need to know the rows returned by this query and you are executing this query anyway somwhere in your code you could simply make use of ##ROWCOUNT function. Something like....
SELECT ...... --<-- Your Query
SELECT ##ROWCOUNT --<-- This will return the number of rows returned
-- by the previous query

You are missing an alias after your subquery
select count(*) from (select ...) v
You can also try to return total count using existing SQL, without using subquery
select p.UserName,
p.FirstName + ' ' + p.LastName as [FullName],
count(b.billid) as [Count],
sum(b.PercentRials) as [Sum],
COUNT(*) over () [TotalCount] ------- total count here
from Bills b
inner join UserProfiles p on b.PayerUserName=p.UserName
where b.Successful=1
group by p.UserName, p.FirstName + ' ' + p.LastName

Try this code:
SELECT COUNT(*)
FROM (
SELECT p.UserName
,p.FirstName + ' ' + p.LastName AS [FullName]
,COUNT(b.billid) AS [Count]
,SUM(b.PercentRials) AS [Sum]
FROM Bills b
INNER JOIN UserProfiles p
ON b.PayerUserName = p.UserName
WHERE b.Successful = 1
GROUP BY p.UserName
,p.FirstName + ' ' + p.LastName
) a
based on your edit. You were missing derived tabled alias.
If you look at FROM clause syntax you will see
| derived_table [ AS ] table_alias [ ( column_alias [ ,...n ] ) ]
When a derived table, rowset or table-valued function, or operator
clause (such as PIVOT or UNPIVOT) is used, the required table_alias at
the end of the clause is the associated table name for all columns,
including grouping columns, returned.
http://technet.microsoft.com/en-us/library/ms177634.aspx

If you have a unique column name in there, you can count that. For example I'm assuming UserName is unique here.
select count(query.UserName) from (
select p.UserName, p.FirstName + ' ' + p.LastName as [FullName]
,count(b.billid) as [Count], sum(b.PercentRials) as [Sum] from Bills b
inner join UserProfiles p on b.PayerUserName=p.UserName
where b.Successful=1
group by p.UserName, p.FirstName + ' ' + p.LastName) as query

COUNT() - aggregate function
SELECT SQL_CALC_FOUND_ROWS * FROM ...;
SELECT FOUND_ROWS(); // next query !!!!

Related

Aggregate function as condition

I'm having problem trying to use aggregate function result as a condition. Basically, I need to select rows that have "View count" more than 3. Here is code that works:
SELECT b.BranchNo AS "Branch Number",
p.PropertyNo || ', ' || p.PostCode || ', ' || p.City || ', ' || p.Street AS "Object address" , count(v.ViewDate) as "View count"
FROM Branch b INNER JOIN PropertyForRent p ON b.BranchNo=p.PropertyBranchNo
INNER JOIN Viewing v ON p.PropertyNo=v.ViewPropertyNo WHERE v.ViewDate>='2014-01-01'
GROUP BY b.BranchNo, p.PropertyNo;
I was trying to use something like that:
HAVING count(v.ViewDate)>=3
But that obviously didn't work. Is there a way of making such condition without using a subquery?
It looks like the fields in your select don't match up with the group by, but other than that, the "condition based on aggregate" is exactly what the having clause is for. For example, this query should work:
SELECT
b.BranchNo AS "Branch Number",
p.PropertyNo || ', ' || p.PostCode || ', ' || p.City || ', ' || p.Street AS "Object address" ,
count(v.ViewDate) as "View count"
FROM Branch b INNER JOIN PropertyForRent p ON b.BranchNo=p.PropertyBranchNo
INNER JOIN Viewing v ON p.PropertyNo=v.ViewPropertyNo WHERE v.ViewDate>='2014-01-01'
GROUP BY b.BranchNo, p.PropertyNo, p.PostCode, p.City, p.Street
HAVING count(v.ViewDate) >= 3;
You need to do grouping in Viewing table sub-query to get the counts. Then join to that.
SELECT b.BranchNo AS [Branch Number],
p.PropertyNo + ', ' + p.PostCode + ', ' + p.City + ', ' + p.Street AS [Object address],
v.ViewCount
FROM Branch b
INNER JOIN PropertyForRent p ON b.BranchNo=p.PropertyBranchNo
INNER JOIN (SELECT ViewPropertyNo, COUNT(*) as ViewCount
FROM Viewing
WHERE v.ViewDate>='2014-01-01'
GROUP BY ViewPropertyNo
) AS v ON p.PropertyNo = v.ViewPropertyNo
WHERE v.ViewCount >= 3;

Getting count over() value after distinct executed

I have a query such as
select
distinct
t.*,
t.name + ' ' + t.lastname as customername
count(t.id) over() as count
from
table t
inner join othertable o
on t.id = o.tableid
where t.blah = 'aaa'
The problem is that the count over() calculates the results before the distinct is executed and therefore returns an incorrect value.
I could remove the distinct and use group by but this will give the count for each group and I want the sum of those values.
I could do a subquery but the problem is this query is getting built up inside an application so I'd have to do some string manipulation to add the where clause to the subquery and main sql body.
Is there a way to get the count show the results after the distinct is executed?
Thanks
This should solve the problem
select count(v.col_a) over() as count,
v.*
from (select distinct t.col_a, t.col_b, ... --all columns you need
t.name + ' ' + t.lastname as customername
from table t
inner join othertable o on t.id = o.tableid
where t.blah = 'aaa') v
Use group by, but use the correct expression:
select t.*,
t.name + ' ' + t.lastname as customername
sum(count(t.id)) over() as total_count
from table t inner join
othertable o
on t.id = o.tableid
where t.blah = 'aaa'
group by . . .

Trying to get a column value of an ancestor when using HIERARCHYID

I'm evaluating the HIERARCHYID data type to see if it'll meet my needs for a project. I was hoping to use it to get the manager of a given employee ID. I'm looking at tables in the AdventureWorks DB (the 2012 version), specifically the Person.Person and HumanResources.Employee tables.
My query goes something like this:
SELECT
pp.LastName + ', ' + pp.FirstName AS Name,
CAST(hre.NationalIdNumber AS BIGINT) AS Id,
hre.LoginID,
hre.OrganizationNode.GetAncestor(1) AS ManagerId,
hre.JobTitle,
hre.BirthDate,
hre.MaritalStatus,
hre.Gender,
hre.HireDate
FROM
Person.Person pp
INNER JOIN
HumanResources.Employee hre ON pp.BusinessEntityID = hre.BusinessEntityID
Now I expected that because GetAncestor() is a CLR function that I'd have been able to do something like hre.OrganizationNode.GetAncestor(1).NationalIdNumber AS ManagerId but I get told that I'm not worthy very fast.
What is it that I'm doing wrong here?
EDIT Later on
Playing around leads me to this but this is hardly optimal (or is it?)
SELECT
pp.LastName + ', ' + pp.FirstName AS Name,
CAST(hre.NationalIdNumber AS BIGINT) AS Id,
hre.LoginID,
NULL AS ManagerId,
hre.JobTitle,
hre.BirthDate,
hre.MaritalStatus,
hre.Gender,
hre.HireDate,
hre.OrganizationLevel
FROM
Person.Person pp
INNER JOIN
HumanResources.Employee hre ON pp.BusinessEntityID = hre.BusinessEntityID
WHERE
OrganizationLevel = 0
UNION
SELECT
pp.LastName + ', ' + pp.FirstName AS Name,
CAST(hre.NationalIdNumber AS BIGINT) AS Id,
hre.LoginID,
CAST(hre2.NationalIDNumber AS BIGINT) AS ManagerId,
hre.JobTitle,
hre.BirthDate,
hre.MaritalStatus,
hre.Gender,
hre.HireDate,
hre.OrganizationLevel
FROM
Person.Person pp
INNER JOIN
HumanResources.Employee hre ON pp.BusinessEntityID = hre.BusinessEntityID
INNER JOIN
HumanResources.Employee hre2 ON hre.OrganizationNode.GetAncestor(1) = hre2.OrganizationNode
ORDER BY
hre.OrganizationLevel ASC
A correlated sub-query seems to do it for me:
SELECT
pp.LastName + ', ' + pp.FirstName AS Name,
CAST(hre.NationalIdNumber AS BIGINT) AS Id,
hre.LoginID,
(
SELECT NationalIDNumber
FROM HumanResources.Employee AS m
WHERE OrganizationNode = hre.OrganizationNode.GetAncestor(1)
)AS ManagerId,
hre.JobTitle,
hre.BirthDate,
hre.MaritalStatus,
hre.Gender,
hre.HireDate
FROM
Person.Person pp
INNER JOIN
HumanResources.Employee hre ON pp.BusinessEntityID = hre.BusinessEntityID

select user doesn't contain a record in other table sql query

I had three tables: sarcuser, sarcusercommittee, sarcallcourse. I need to build a query that brings all the users that don't have a committee (they don't have a record in sarcusercommittee). Here is my current query:
SELECT u.firstname + ' ' + u.lastname AS name, u.dateofbirth, u.gender, LEFT(u.note, 200) AS note, c.name AS coursename
FROM sarcuser AS u INNER JOIN
sarcusercommittee AS uc ON u.id = uc.user_id INNER JOIN
sarcallcourse AS c ON c.id = u.courseid
WHERE ((SELECT COUNT(id) AS Expr1
FROM sarcusercommittee
WHERE (user_id = u.id)) = 0)
ORDER BY name DESC
I guess the problem is in (ON condistion) but don't get it ... any help ?
NOTE : I use visual studio 2010
SELECT u.firstname + ' ' + u.lastname AS name, u.dateofbirth, u.gender, LEFT(u.note, 200) AS note, c.name AS coursename
FROM sarcuser AS u
INNER JOIN sarcallcourse AS c
ON c.id = u.courseid
WHERE u.id NOT IN (
SELECT uc.user_id
FROM sarcusercommittee AS uc
)
ORDER BY name DESC
Firstly you shouldn't inner join onto sarcusercommittee if you dont want rows from it. Seconly I would filter to the users that are not in sarcusercommittee using NOT IN.

SQL Fewer Columns Than Were Specified

I'm running the following query in SQL server and it's giving me the error:
'Results' has fewer columns than were specified in the column list.
I'm clearly listing several columns so I'm not sure what the problem is. I tried putting only Results( ContractDesc ) and it resolved the error, so I guess it thinks I'm only selecting one column inside that query. How do I solve this?
SELECT
Cl.LegalName AS ClientNames,
Results.ContractDesc AS ContractNames,
Results.ProjectNames AS ProjectNames,
Results.EmployeeNames AS EmployeeNames,
Results.TotalHours AS TotalHours,
Results.TotalCharges AS TotalCharges,
Results.BillingContacts AS BillingContacts
FROM Clients Cl
CROSS APPLY (
SELECT
( Cr.ContractDesc + ', ' ) AS ContractDesc,
( P.ProjectName + ', ' ) AS ProjectNames,
( E.FirstName + ' ' + E.LastName + ', ' ) AS EmployeeNames,
( WH.HoursWorked + ', ' ) AS TotalHours,
( WH.HoursWorked * BR.Rate ) + ', ' AS TotalCharges,
( Ca.FirstName + Ca.LastName + ', ' + Ca.AddrLine1 + ', ' ) AS BillingContacts
FROM Contracts Cr
JOIN Projects P ON( Cr.ContractID = P.ContractID )
JOIN EmployeesProjects EP ON( P.ProjectID = EP.ProjectID )
JOIN Employees E ON( EP.EmpID = E.EmpID )
JOIN WorkHours WH ON( E.EmpID = WH.EmpID )
JOIN BillingRates BR ON( E.TitleID = BR.TitleID ) AND ( E.Level = BR.Level )
JOIN ContractsContacts CC ON( Cr.ContractID = CC.ContractID )
JOIN Contacts Ca ON( CC.ContactID = Ca.ContactID )
WHERE( Cl.ClientID = Cr.ClientID )
AND ( WH.WH_Month = 4 )
AND ( WH.WH_Year = 2013 )
GROUP BY Cr.ContractID,
Cr.ContractDesc,
P.ProjectName,
E.FirstName,
E.LastName,
WH.HoursWorked,
BR.Rate,
Ca.FirstName,
Ca.LastName,
Ca.AddrLine1
FOR XML PATH( '' )
) Results ( ContractDesc, ProjectNames, EmployeeNames, TotalHours, TotalCharges, BillingContacts )
ClientNames appears to be missing from Results().