SQL Server: How can I use the COUNT clause without GROUPing? - sql

I'm looking get two things from a query, given a set of contraints:
The first match
The total number of matches
I can get the first match by:
SELECT TOP 1
ID,
ReportYear,
Name,
SignDate,
...
FROM Table
WHERE
...
ORDER BY ... //I can put in here which one I want to take
And then I can get the match count if I use
SELECT
MIN(ID),
MIN(ReportYear),
MIN(Name),
MIN(SignDate),
... ,
COUNT(*) as MatchCount
FROM Table
WHERE
...
GROUP BY
??? // I don't really want any grouping
I really want to avoid both grouping and using an aggregate function on all my results. This question SQL Server Select COUNT without using aggregate function or group by suggests the answer would be
SELECT TOP 1
ID,
ReportYear,
Name,
SignDate,
... ,
##ROWCOUNT as MatchCount
FROM Table
This works without the TOP 1, but when it's in there, ##ROWCOUNT = number of rows returned, which is 1. How can I get essentially the output of COUNT(*) (whatever's left after the where clause) without any grouping or need to aggregate all the columns?
What I don't want to do is repeat each of these twice, once for the first row and then again for the ##ROWCOUNT. I'm not finding a way I can properly use GROUP BY, because I strictly want the number of items that match my criteria, and I want columns that if I GROUPed them would throw this number off - unless I'm misunderstanding GROUP BY.

Assuming you are using a newish version of SQL Server (2008+ from memory) then you can use analytic functions.
Simplifying things somewhat, they are a way of way of doing an aggregate over a set of data instead of a group - an extension on basic aggregates.
Instead of this:
SELECT
... ,
COUNT(*) as MatchCount
FROM Table
WHERE
...
You do this:
SELECT
... ,
COUNT(*) as MatchCount OVER (PARTITION BY <group fields> ORDER BY <order fields> )
FROM Table
WHERE
...
GROUP BY
Without actually running some code, I can't recall exactly which aggregates that you can't use in this fashion. Count is fine though.

Well, you can use OVER clause, which is an window function.
SELECT TOP (1)
OrderID, CustID, EmpID,
COUNT(*) OVER() AS MatchCount
FROM Sales.Orders
WHERE OrderID % 2 = 1
ORDER BY OrderID DESC

Try next query:
select top 1
*, count(*) over () rowsCount
from
(
select
*, dense_rank() over (order by ValueForOrder) n
from
myTable
) t
where
n = 1

Related

how to get count of total number of rows following a group by?

I wanted to group some data and then count the number of rows after the duplicate data has been combined into groups.
data:
idx
7706
7706
1000
want to return total count = 2
select count(*) (
select nb.idx
group by nb.idx
) as test
First thing that came to mind was this.
and then I saw someone do this
select count(*) over()
group by nb.idx
I'm not sure I totally understand this second one, but I wanted to try various things and compare the speed of the various methods.
use count(distinct idx)
select count(distinct idx)
from tablname
Try below query..
select count(*), nb.idx from table_name
group by nb.idx

Get Total Sum with User Sum

SQL Table:
UserId ReportsRead
1 4
2 6
3 5
I would like to query that table so that I can get the following out:
UserId ReportsRead TotalReports
1 4 15
The problem is that because I apply the WHERE clause the sum I get will be the same as users reports read.
SELECT UserId, ReportsRead, SUM(ReportsRead) AS TotalReports FROM MyTable WHERE UserId = 1
Is there a built in function that will allow me to do this? I would like to avoid Sub-queries entirely.
I don't usually recommend subqueries in this situation, but in this case, it seems like a simple approach:
SELECT UserId, ReportsRead,
(SELECT SUM(ReportsRead) from MyTable) AS TotalReports
FROM MyTable
WHERE UserId = 1;
If you want rows for all users, then window functions are the way to go:
select t.*, sum(reportsread) over () as totalreports
from mytable;
However, you can't include a where clause and still expect to get the correct total.
Use the sum window function.
SELECT UserId, ReportsRead, SUM(ReportsRead) OVER() AS TotalReports
FROM MyTable
Use a filtering condition to get a specific userId like
SELECT *
FROM (SELECT UserId, ReportsRead, SUM(ReportsRead) OVER() AS TotalReports
FROM MyTable
) t
WHERE UserId=1

How to sum two columns in sql without group by

I have columns such as pagecount, convertedpages and changedpages in a table along with many other columns.
pagecount is the sum of convertedpages and changedpages.
I need to select all rows along with pagecount and i cant group them. I am wondering if there is any way to do it?
This select is part of view. so can i use another sql statement to bring just the sum and then somehow make it part of the main sql query?
Thank you.
SELECT
*,
(ConvertedPages + ChangedPages) as PageCount
FROM Table
If I'm understanding your question correctly, while I'm not sure why you can't use group by, another option would be to use a correlated subquery:
select distinct id,
(select sum(field) from yourtable y2 where y.id = y2.id) summedresult
from yourtable y
This assumes you have data such as:
id | field
1 | 10
1 | 15
2 | 10
And would be equivalent to:
select id, sum(field)
from yourtable
group by id
Not 100% on what you're after here, but if you want a total across rows without grouping, you can use OVER() with an aggregate in SQL Server:
SELECT *, SUM(convertedpages) OVER() AS convertedpages
, SUM(changedpages) OVER() AS changedpages
, SUM(changedpages + convertedpages) OVER() as PageCount
FROM Table
This repeats the total for every row, you can use PARTITION BY inside OVER() if you'd like to have the aggregate to be grouped by some fields while still displaying the full detail of all rows.

Sort by count SQL reporting services

I have a simple query in a tabloid control that gets all the leads in one month. I then use the tabloid control to group them into lead source. And then I have an associated count column. I want to sort my report on the count descending, without doing it in the query. I keep getting an error saying you cannot sort on an aggregate.
Thanks.
you can do one more thing..
just write your query in subquery part and write order by clause in outer query.
(suppose you have group by query as follow-
select lead_source, count(*) cnt
from your_table
group by lead_source
)
so you can do as follow -
select lead_source, cnt from (
select lead_source, count(*) cnt
from your_table
group by lead_source
)
order by cnt
this your_table and group by column list you have to edit accordingly your table structure ..

adding count( ) column on each row

I'm not sure if this is even a good question or not.
I have a complex query with lot's of unions that searches multiple tables for a certain keyword (user input). All tables in which there is searched are related to the table book.
There is paging on the resultset using LIMIT, so there's always a maximum of 10 results that get withdrawn.
I want an extra column in the resultset displaying the total amount of results found however. I do not want to do this using a separate query. Is it possible to add a count() column to the resultset that counts every result found?
the output would look like this:
ID Title Author Count(...)
1 book_1 auth_1 23
2 book_2 auth_2 23
4 book_4 auth_.. 23
...
Thanks!
This won't add the count to each row, but one way to get the total count without running a second query is to run your first query using the SQL_CALC_FOUND_ROWS option and then select FOUND_ROWS(). This is sometimes useful if you want to know how many total results there are so you can calculate the page count.
Example:
select SQL_CALC_FOUND_ROWS ID, Title, Author
from yourtable
limit 0, 10;
SELECT FOUND_ROWS();
From the manual:
http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_found-rows
The usual way of counting in a query is to group on the fields that are returned:
select ID, Title, Author, count(*) as Cnt
from ...
group by ID, Title, Author
order by Title
limit 1, 10
The Cnt column will contain the number of records in each group, i.e. for each title.
Regarding second query:
select tbl.id, tbl.title, tbl.author, x.cnt
from tbl
cross join (select count(*) as cnt from tbl) as x
If you will not join to other table(s):
select tbl.id, tbl.title, tbl.author, x.cnt
from tbl, (select count(*) as cnt from tbl) as x
My Solution:
SELECT COUNT(1) over(partition BY text) totalRecordNumber
FROM (SELECT 'a' text, id_consult_req
FROM consult_req cr);
If your problem is simply the speed/cost of doing a second (complex) query I would suggest you simply select the resultset into a hash-table and then count the rows from there while returning, or even more efficiently use the rowcount of the previous resultset, then you do not even have to recount
This will add the total count on each row:
select count(*) over (order by (select 1)) as Cnt,*
from yourtable
Here is your answare:
SELECT *, #cnt count_rows FROM (
SELECT *, (#cnt := #cnt + 1) row_number FROM your_table
CROSS JOIN (SELECT #cnt := 0 AS variable) t
) t;
You simply cannot do this, you'll have to use a second query.