What is happening that messes up my GROUP BY query? - sql-server

This is my Query:
select top 60 * from ABC_Sessions (nolock)
where EntryDate > '06-22-2012 23:59:59'
GROUP BY TargetedID
then it gives me this error:
Msg 8120, Level 16, State 1, Line 1 Column 'BI_Sessions.SessionID' is
invalid in the select list because it is not contained in either an
aggregate function or the GROUP BY clause.

The * in your query expands to all the columns in your table.
select top 60 TargetedID, SessionID, ...
from ABC_Sessions (nolock)
where EntryDate > '06-22-2012 23:59:59'
GROUP BY TargetedID
As the error message states, it's not valid to select SessionID without an aggregate function (e.g. MAX).
This would work:
select top 60 TargetedID, MAX(SessionID) AS MaxSessionID
from ABC_Sessions (nolock)
where EntryDate > '06-22-2012 23:59:59'
GROUP BY TargetedID

You used star * but not group by columns from abc_sessions table.
Using GROUP BY without any aggregate function looks strange for me.
What would you like to see?

It's a matter of theory: as the error says, you're not allowed to SELECT something that you have not at your disposal.
So, when you use a simple SELECT / FROM / WHERE query, everything you have in your FROM tables is OK for you to select.
But if you use a GROUP BY, you're narrowing your view: anything you don't use in your GROUP BY is discarded (think it twice, it makes no sense to select data from several lines when you explicitly ask to group those lines).
Maybe you're confusing GROUP BY and ORDER BY?

The reason why you are getting this error is because you are not using either sum/average/count/max/min or any similar functions in the select statement of yours. Once you use any of them, you won't get this error. ex :
select top 60 TargetedID, MAX(EntryDate)
from ABC_Sessions (nolock)
where EntryDate > '06-22-2012 23:59:59'
GROUP BY TargetedID

Related

Select distinct records from MS SQL database when querying row numbers

This query returns 5 identical products, because there are 5 keywords associated with the resulting product:
SELECT
products.field1,
products.field2
FROM products,
keywords
WHERE products.itemnum = keywords.itemnum
AND products.itemnum = 123
ORDER BY products.field1, products.field2
If I put a "distinct" after "select", then I get 1 result, which is what I want.
However, when I setup my query like this:
SELECT
*
FROM (SELECT
ROW_NUMBER() OVER (ORDER BY products.field1, products.field2) AS rownum,
products.field1,
products.field2
FROM products,
keywords
WHERE products.itemnum = keywords.itemnum
AND products.itemnum = 123) AS qryresults
WHERE rownum >= 1
AND rownum <= 20
I get 5 identical products again. There doesn't seem to be anywhere I can put a "distinct" statement to limit it to 1 result. I'm sure the reason is that by adding the row numbers, that doesn't make the results "distinct" anymore.
I am using the technique shown in this query to limit potentially large search results to only 20 records at a time, which greatly reduces overhead and speeds up my query. So if there are 100,000 results, I can easily set this up to return records 90,000-90,020, for example.
MySQL has this kind of thing built-in, but with MS SQL this is the workaround.
However, I am having trouble figuring out how to make it work when I am combining the keywords table.
If I replace the * with a list of columns, then I get an error:
The multi-part identifier could not be bound.
I'm not sure what else to try. Is there a way to correct this?
Thank you.
Use a CTE to separate the distinct and the ROW_NUMBER() function:
with cte as (select distinct products.field1
, products.field2
from products, keywords
where products.itemnum=keywords.itemnum and products.itemnum=123),
row_n as (select field1
, field2
, row_number() over (order by field1, field2) as rownum
from cte)
select field1, field2
from row_n
where rownum>=1 and rownum<=20

TSQL sub query invalid column and only one expression

It has been a while since writing T-SQL for me and I know this can be done but my memory is good enough to get me close (I think I'm close) but poor enough to not get it right.
To start I have this query:
SELECT DISTINCT(COMM_TYPE),
COUNT(COMM_TYPE) AS 'Total'
FROM
[MYDB].[dbo].[COMM]
GROUP BY
COMM_TYPE
Which returns:
COMM_TYPE Total
--------------------------
TypeA 1
TypeB 44474
TypeC 3
TypeD 3854
TypeE 12327
TypeF 362912
TypeG 484344
TypeH 386
TypeI 106
This is an accurate result.
So now I want the above PLUS a sample of each one. Something with columns like:
ID COMM_TYPE TOTAL DATA COMMENTS PRIMARY COMM_NUMBER
I believe this can be done with a sub query but I am not writing it correctly as I get two errors.
Msg 207, Level 16, State 1, Line 10
Invalid column name 'CT'.
Msg 116, Level 16, State 1, Line 7
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
The second error I understand. My sub query has two columns being returned but positioned in the select as I have it wants only one.
The first error I'm more lost on. I thought I could reference an sub query column in the outer query?
Here is the query:
SELECT TOP(1)
*,
(SELECT
DISTINCT(COMM_TYPE),
COUNT(COMM_TYPE)
FROM
[MYDB].[dbo].[COMM]
GROUP BY
COMM_TYPE) AS CT
FROM
[MYDB].[dbo].[COMM]
WHERE
CT = COMM_TYPE
This is mostly for myself but if it helps anyone here ya go:
We start with a (cte to wrap the entire operation as it bring many benefits but the two applicable here are:
1.Enable grouping by a column that is derived from a scalar subselect.
2.Reference the resulting table multiple times in the same statement
WITH T
AS (
CTE SELECT Statement
)
FINAL SELECT Statement
Next our CTE select basically return three columns for us.
1.Total which in my query was COUNT on a column
2.RN which is the row number
3.Wildcard * which gets all the columns from the table
Now from this point we get into the Partitioning....
So it seems that we need to choose how we are going to break this table up. Since I had defined DISTINCT(COMM_TYPE) without realizing it there was my partition....in that first column definition we also do a count(*). So what must be happening is that first SQL engine breaks table into pieces (partitions) then does a count of records in those pieces....????
SELECT Count(*)
OVER (PARTITION BY COMM_TYPE) AS Total,
Next we do a row_number() operation OVER (aka operating against) again my partition of COMM_TYPE...we then order it and project the column name of rn....kinda not sure why this is needed till I got to the end then it made sense.
Row_number()
OVER (PARTITION BY COMM_TYPE
ORDER BY COMM_TYPE) AS RN,
finally we just pull a wildcard which is every column in the table.
So in the depths of the SQL engine namespace memory registers this must be quite a big hunk of data with these repeated grouping operations "OVER" everything.
However all we see is a single row and that is because of the last select which gives me everything all mushed together as I wanted and we only get the TOP(1) because of that RN column I didn't understand earlier.
Do I understand it properly?
This should do what you need.
WITH T
AS (SELECT Count(*)
OVER (PARTITION BY COMM_TYPE) AS Total,
Row_number()
OVER (PARTITION BY COMM_TYPE
ORDER BY COMM_TYPE) AS RN,
*
FROM MyDb.dbo.Comm)
SELECT *
FROM T
WHERE RN = 1

Row_Number Over Where RowNumber between

I'm try to select a certain rows from my table using the row_number over. However, the sql will prompt the error msg "Invalid column name 'ROWNUMBERS' ". Anyone can correct me?
SELECT ROW_NUMBER() OVER (ORDER BY Price ASC) AS ROWNUMBERS, *
FROM Product
WHERE ROWNUMBERS BETWEEN #fromCount AND #toCount
Attempting to reference the aliased column in the WHERE clause does not work because of the logical query processing taking place. The WHERE is evaluated before the SELECT clause. Therefore, the column ROWNUMBERS does not exist when WHERE is evaluated.
The correct way to reference the column in this example would be:
SELECT a.*
FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Price ASC) AS ROWNUMBERS, *
FROM Product) a
WHERE a.ROWNUMBERS BETWEEN #fromCount AND #toCount
For your reference, the order for operations is:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
There is another answer here that solves the specific error reported. However, I also want to address the wider problem. It looks a lot like what you are doing here is paging your results for display. If that is the case, and if you can use Sql Server 2012, there is a better way now. Take a look at OFFSET/FETCH:
SELECT First Name + ' ' + Last Name
FROM Employees
ORDER BY First Name
OFFSET 10 ROWS FETCH NEXT 5 ROWS ONLY;
That would show the third page of a query where the page size is 5.

Querying aggregate columns in a SQL Server SELECT statement

I have a SQL Server query which runs just fine -- until I add a computed column to the SELECT statement. Then I get an odd SQL Server error.
Here's the SQL:
SELECT
outmail_.MessageID_,
CONVERT(VARCHAR(10),outmail_.Created_,120) AS 'Issue',
lyrReportSummaryData.mailed,
lyrReportSummaryData.successes,
COUNT(*) AS 'opens',
COUNT(DISTINCT clicktracking_.MemberID_) AS 'unique_opens',
convert(decimal(3,1),((convert(float,[unique_opens]))/[successes]) * 100) AS 'Rate'
FROM
outmail_
RIGHT JOIN
clicktracking_ ON clicktracking_.MessageID_ = outmail_.MessageID_
RIGHT JOIN
lyrReportSummaryData ON lyrReportSummaryData.id = clicktracking_.MessageID_
GROUP BY
outmail_.MessageID_, CONVERT(VARCHAR(10), outmail_.Created_,120),
lyrReportSummaryData.mailed, lyrReportSummaryData.successes
The problem is the line beginning with the convert(decimal ... When it is included, I get the following error:
Error 8120: Column 'lyrReportSummaryData.unique_opens' is invalid in
the select list because it is not contained in either an aggregate
function or the GROUP BY clause.
I'm not sure how to resolve the error since I don't know how to use it in a GROUP BY clause (and it doesn't seem that I should need to do so).
Any suggestions for how to proceed? Thanks.
I'm sure someone with better DBA skills than me can point out a more efficient way of doing this, but...
If you perform the bulk of your query as an sub-query, you can then do the calculations on the result of your sub-query:
SELECT
MessageID_,
Issue,
mailed,
successes,
opens,
unique_opens,
convert(decimal(3,1),((convert(float,[unique_opens]))/[successes]) * 100) AS 'Rate'
FROM
(SELECT
outmail_.MessageID_,
CONVERT(VARCHAR(10),outmail_.Created_,120) AS 'Issue',
lyrReportSummaryData.mailed,
lyrReportSummaryData.successes,
COUNT(*) AS 'opens',
COUNT(DISTINCT clicktracking_.MemberID_) AS 'unique_opens'
FROM outmail_
RIGHT JOIN clicktracking_ ON clicktracking_.MessageID_ = outmail_.MessageID_
RIGHT JOIN lyrReportSummaryData ON lyrReportSummaryData.id = clicktracking_.MessageID_
GROUP BY outmail_.MessageID_, CONVERT(VARCHAR(10), outmail_.Created_,120), lyrReportSummaryData.mailed, lyrReportSummaryData.successes
) subquery /* was 'g' */
Effectively what this does is runs the grouping, and then based on that, does the calculation afterwards.
Subqueries must be given an alias (in this instance 'subquery') - even if you don't use that alias name.

SQL Error with Order By in Subquery

I'm working with SQL Server 2005.
My query is:
SELECT (
SELECT COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
GROUP BY refKlinik_id
ORDER BY refKlinik_id
) as dorduncuay
And the error:
The ORDER BY clause is invalid in views, inline functions, derived
tables, subqueries, and common table expressions, unless TOP or FOR
XML is also specified.
How can I use ORDER BY in a sub query?
This is the error you get (emphasis mine):
The ORDER BY clause is invalid in
views, inline functions, derived
tables, subqueries, and common table
expressions, unless TOP or FOR XML is
also specified.
So, how can you avoid the error? By specifying TOP, would be one possibility, I guess.
SELECT (
SELECT TOP 100 PERCENT
COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
GROUP BY refKlinik_id
ORDER BY refKlinik_id
) as dorduncuay
If you're working with SQL Server 2012 or later, this is now easy to fix. Add an offset 0 rows:
SELECT (
SELECT
COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
GROUP BY refKlinik_id
ORDER BY refKlinik_id OFFSET 0 ROWS
) as dorduncuay
Besides the fact that order by doesn't seem to make sense in your query....
To use order by in a sub select you will need to use TOP 2147483647.
SELECT (
SELECT TOP 2147483647
COUNT(1) FROM Seanslar WHERE MONTH(tarihi) = 4
GROUP BY refKlinik_id
ORDER BY refKlinik_id
) as dorduncuay
My understanding is that "TOP 100 PERCENT" doesn't gurantee ordering anymore starting with SQL 2005:
In SQL Server 2005, the ORDER BY
clause in a view definition is used
only to determine the rows that are
returned by the TOP clause. The ORDER
BY clause does not guarantee ordered
results when the view is queried,
unless ORDER BY is also specified in
the query itself.
See SQL Server 2005 breaking changes
Hope this helps,
Patrick
If building a temp table, move the ORDER BY clause from inside the temp table code block to the outside.
Not allowed:
SELECT * FROM (
SELECT A FROM Y
ORDER BY Y.A
) X;
Allowed:
SELECT * FROM (
SELECT A FROM Y
) X
ORDER BY X.A;
You don't need order by in your sub query. Move it out into the main query, and include the column you want to order by in the subquery.
however, your query is just returning a count, so I don't see the point of the order by.
A subquery (nested view) as you have it returns a dataset that you can then order in your calling query. Ordering the subquery itself will make no (reliable) difference to the order of the results in your calling query.
As for your SQL itself:
a) I seen no reason for an order by as you are returning a single value.
b) I see no reason for the sub query anyway as you are only returning a single value.
I'm guessing there is a lot more information here that you might want to tell us in order to fix the problem you have.
Add the Top command to your sub query...
SELECT
(
SELECT TOP 100 PERCENT
COUNT(1)
FROM
Seanslar
WHERE
MONTH(tarihi) = 4
GROUP BY
refKlinik_id
ORDER BY
refKlinik_id
) as dorduncuay
:)
maybe this trick will help somebody
SELECT
[id],
[code],
[created_at]
FROM
( SELECT
[id],
[code],
[created_at],
(ROW_NUMBER() OVER (
ORDER BY
created_at DESC)) AS Row
FROM
[Code_tbl]
WHERE
[created_at] BETWEEN '2009-11-17 00:00:01' AND '2010-11-17 23:59:59'
) Rows
WHERE
Row BETWEEN 10 AND 20;
here inner subquery ordered by field created_at (could be any from your table)
In this example ordering adds no information - the COUNT of a set is the same whatever order it is in!
If you were selecting something that did depend on order, you would need to do one of the things the error message tells you - use TOP or FOR XML
Try moving the order by clause outside sub select and add the order by field in sub select
SELECT * FROM
(SELECT COUNT(1) ,refKlinik_id FROM Seanslar WHERE MONTH(tarihi) = 4 GROUP BY refKlinik_id)
as dorduncuay
ORDER BY refKlinik_id
For me this solution works fine as well:
SELECT tbl.a, tbl.b
FROM (SELECT TOP (select count(1) FROM yourtable) a,b FROM yourtable order by a) tbl
Good day
for some guys the order by in the sub-query is questionable.
the order by in sub-query is a must to use if you need to delete some records based on some sorting.
like
delete from someTable Where ID in (select top(1) from sometable where condition order by insertionstamp desc)
so that you can delete the last insertion form table.
there are three way to do this deletion actually.
however, the order by in the sub-query can be used in many cases.
for the deletion methods that uses order by in sub-query review below link
http://web.archive.org/web/20100212155407/http://blogs.msdn.com/sqlcat/archive/2009/05/21/fast-ordered-delete.aspx
i hope it helps. thanks you all
For a simple count like the OP is showing, the Order by isn't strictly needed. If they are using the result of the subquery, it may be. I am working on a similiar issue and got the same error in the following query:
-- I want the rows from the cost table with an updateddate equal to the max updateddate:
SELECT * FROM #Costs Cost
INNER JOIN
(
SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
FROM #HoldCosts cost
GROUP BY Entityname, costtype
ORDER BY Entityname, costtype -- *** This causes an error***
) CostsMax
ON Costs.Entityname = CostsMax.entityname
AND Costs.Costtype = CostsMax.Costtype
AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
ORDER BY Costs.Entityname, Costs.costtype
-- *** To accomplish this, there are a few options:
-- Add an extraneous TOP clause, This seems like a bit of a hack:
SELECT * FROM #Costs Cost
INNER JOIN
(
SELECT TOP 99.999999 PERCENT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
FROM #HoldCosts cost
GROUP BY Entityname, costtype
ORDER BY Entityname, costtype
) CostsMax
ON Costs.Entityname = CostsMax.entityname
AND Costs.Costtype = CostsMax.Costtype
AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
ORDER BY Costs.Entityname, Costs.costtype
-- **** Create a temp table to order the maxCost
SELECT Entityname, costtype, MAX(updatedtime) MaxUpdatedTime
INTO #MaxCost
FROM #HoldCosts cost
GROUP BY Entityname, costtype
ORDER BY Entityname, costtype
SELECT * FROM #Costs Cost
INNER JOIN #MaxCost CostsMax
ON Costs.Entityname = CostsMax.entityname
AND Costs.Costtype = CostsMax.Costtype
AND Costs.UpdatedTime = CostsMax.MaxUpdatedtime
ORDER BY Costs.Entityname, costs.costtype
Other possible workarounds could be CTE's or table variables. But each situation requires you to determine what works best for you. I tend to look first towards a temp table. To me, it is clear and straightforward. YMMV.
On possible needs to order a subquery is when you have a UNION :
You generate a call book of all teachers and students.
SELECT name, phone FROM teachers
UNION
SELECT name, phone FROM students
You want to display it with all teachers first, followed by all students, both ordered by. So you cant apply a global order by.
One solution is to include a key to force a first order by, and then order the names :
SELECT name, phone, 1 AS orderkey FROM teachers
UNION
SELECT name, phone, 2 AS orderkey FROM students
ORDER BY orderkey, name
I think its way more clear than fake offsetting subquery result.
I Use This Code To Get Top Second Salary
I am Also Get Error Like
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
TOP 100 I Used To Avoid The Error
select * from (
select tbl.Coloumn1 ,CONVERT(varchar, ROW_NUMBER() OVER (ORDER BY (SELECT 1))) AS Rowno from (
select top 100 * from Table1
order by Coloumn1 desc) as tbl) as tbl where tbl.Rowno=2

Resources