How To Get Count of the records in sql - sql

I have 2 tables in my database one tblNews and another tblNewsComments
I want to select 10 records from tblNewsComments than have must Comments of news
I used this query but it give an error
SELECT tblNews.id,
tblNews.newsTitle,
tblNews.createdate,
tblNews.viewcount,
COUNT(tblNewsComments.id) AS comcounts
FROM tblNews
INNER JOIN tblNewsComments ON tblNews.id = tblNewsComments.newsID
GROUP BY tblNews.id

Try to replace
GROUP BY tblNews.id
With
GROUP BY tblNews.id,
tblNews.newsTitle,
tblNews.createdate,
tblNews.viewcount
All the expressions in the SELECT list should be in the GROUP BY or inside an aggregate function.

I've always found this to be an annoyance in SQL. There's nothing logically wrong with your query; you're grouping by news item and selecting various attributes of the news item, and then selecting the count of comments linked to the news item. That makes sense.
The error arises because the SQL engine isn't smart enough to realize that all the columns in tblNews are at the same data context, and that grouping by tblNews.id effectively guarantees that there will only be one newsTitle, createdate, and viewcount for each group. It should be able to realize that, I think, and carry out the query. But it doesn't do that; the only column it considers to be unique in the group data context is the exact column that you grouped by, id.
One solution, as Multisync just posted, is to group by ALL the columns you want to include in the select clause. I don't think this is the best solution, however, as you shouldn't have to specify all those columns in the group by clause, and that would force you to keep adding to that list whenever you want to add a new TblNews column to the select clause.
The solution I've always used is to wrap the column in an ineffectual aggregate function in the select clause; I always use max():
select
tblNews.id,
max(tblNews.newsTitle),
max(tblNews.createdate),
max(tblNews.viewcount),
count(tblNewsComments.id) comcounts
from
tblNews
inner join tblNewsComments on tblNews.id=tblNewsComments.newsID
group by
tblNews.id
;

Or with subquery:
SELECT n.id,
n.newsTitle,
n.createdate,
n.viewcount,
(SELECT COUNT(*) FROM tblNewsComments c ON n.id = c.newsID) AS comcounts
FROM tblNews n

you have to select one column and group by another...other column will not work as they are not in the aggregate function.
SELECT tblNews.id, COUNT(tblNewsComments.newsID) AS comcounts
FROM tblNews
INNER JOIN tblNewsComments ON tblNews.id = tblNewsComments.newsID
GROUP BY tblNews.id
Read Here

Related

SQL subselect statement very slow on certain machines

I've got an sql statement where I get a list of all Ids from a table (Machines).
Then need the latest instance of another row in (Events) where the the id's match so have been doing a subselect.
I need to latest instance of quite a few fields that match the id so have these subselects after one another within this single statement so end up with results similar to this...
This works and the results are spot on, it's just becoming very slow as the Events Table has millions of records. The Machine table would have on average 100 records.
Is there a better solution that subselects? Maybe doing inner joins or a stored procedure?
Help appreciated :)
You can use apply. You don't specify how "latest instance" is defined. Let me assume it is based on the time column:
Select a.id, b.*
from TableA a outer apply
(select top(1) b.Name, b.time, b.weight
from b
where b.id = a.id
order by b.time desc
) b;
Both APPLY and the correlated subquery need an ORDER BY to do what you intend.
APPLY is a lot like a correlated query in the FROM clause -- with two convenient enhances. A lateral join -- technically what APPLY does -- can return multiple rows and multiple columns.

TSQL Distinct does not work

I have the following query and I try to keep a unique value for each GLOBAL_CONTENT_ID using the DISTINCT keyword. Unfortunately I cannot make it work.
SELECT DISTINCT
CD.GLOBAL_CONTENT_ID, CD.DOWNLOAD_ID, PA.PHYSICAL_ASSET_ID
FROM
[CONTENT_DOWNLOAD] CD
INNER JOIN
PHYSICAL_ASSET AS PA ON CD.GLOBAL_CONTENT_ID = PA.GLOBAL_CONTENT_ID
WHERE
CD.UPC = '00600753515501'
ORDER BY
CD.GLOBAL_CONTENT_ID
Any idea?
Thanks
The DISTINCT keyword will ensure that no duplicate records appear in your result set. However, it makes no guarantee that a given column cannot have duplicate values across multiple records, if the combination of values in those records be distinct.
One option to get the distinct GLOBAL_CONTENT_ID values would be to use the following query:
SELECT DISTINCT CD.GLOBAL_CONTENT_ID
FROM [CONTENT_DOWNLOAD] CD
INNER JOIN PHYSICAL_ASSET AS PA ON CD.GLOBAL_CONTENT_ID = PA.GLOBAL_CONTENT_ID
WHERE CD.UPC = '00600753515501'
ORDER BY CD.GLOBAL_CONTENT_ID
DISTINCT works on every column in the SELECT clause, not just a single column. If one of those columns has a different value, then the row is considered different and returned as another row. In your query, you are including 'PHYSICAL_ASSET_ID' which has a different value for each row which is why you are getting multiple rows.

Aggregate function in SQL Server

I'm getting really frustrated about SQL Server. I'm just trying to join 3 tables, very simple and easily done in mysql. But in SQL Server it keeps telling me to contain tbl_department.deptname in an aggregate function. But what aggregate function could I possibly use in a simple string?
SELECT
COUNT(tblStudent_Department.student_id) AS Expr2,
tbl_department.deptname AS Expr1
FROM
tblStudent_Department
LEFT OUTER JOIN
tbl_department ON tblStudent_Department.deptcode = tbl_department.deptcode
LEFT OUTER JOIN
tblStudent ON tblStudent_Department.student_id = tblStudent.studentid
GROUP BY
tblStudent_Department.deptcode
Please help.
The database doesn't know that if you group on deptcode, you're implicitly grouping on deptname. You must tell SQL Server this by adding the column to the group by:
GROUP BY tblStudent_Department.deptcode, tbl_department.deptname
MySQL is special in that it basically picks a random row if you don't specify an aggregate. This can be misleading and lead to wrong results. As in many other things, MySQL has the more pragmatic solution, and SQL Server the more correct one.
The problem is because your GROUP BY and SELECT terms don't match up.
The simplest way to fix this is to add tbl_department.deptname into your GROUP BY, like so:
GROUP BY tblStudent_Department.deptcode, tbl_department.deptname
You're grouping by deptcode but selecting deptname - if you don't want to aggregate the department (which sounds like it makes sense) then you need to have the deptname in the "group by" statement:
SELECT COUNT(tblStudent_Department.student_id) AS Expr2, tbl_department.deptname AS Expr1
FROM tblStudent_Department
LEFT OUTER JOIN tbl_department ON tblStudent_Department.deptcode = tbl_department.deptcode
LEFT OUTER JOIN tblStudent ON tblStudent_Department.student_id = tblStudent.studentid
GROUP BY tblStudent_Department.deptname
Note I've removed the deptcode because I don't think you need it
If you're using aggregate functions (sum, count etc) ALL fields returned in your select statement need to either be aggregated OR in the group by clause.
First, Last, or put it into the group by.
The rule are:
IF you use a group by, every field is either one of the grouping fields OR one of the aggregated fields.
If you select tbl_department.deptname then you have to either group by that, too, or say WHICH ONE is taken.
Some aggretgate functions are faking that nicely - First, Last (take first or last occurance).

does the order of columns in a SQL select matters?

my question is regarding a left join I've tried to count how many people are tracking a certain project.
(there can be zero followers)
now the only way i can get it to work is by adding
group by idproject
my question is if the is a way to avoid using this and only selecting and implicitly
setting that group option.
SQL:
select `project_view`.`idproject` AS `idproject`,
count(`track`.`iduser`) AS `c`,`name`
from `project_view` left join `track` using(idproject)
I expected it count null as zero but it doesn't appear at all, if i neglect counting then it shows as null where there are no followers.
If you have a WHERE clause to specify a certain project then you don't need a GROUP BY.
SELECT project_view.idproject, COUNT(track.iduser) AS c, name
FROM project_view
LEFT JOIN track USING (idproject)
WHERE idproject = 4
If you want a count for each project then you do need a GROUP BY.
SELECT project_view.idproject, COUNT(track.iduser) AS c, name
FROM project_view
LEFT JOIN track USING (idproject)
GROUP BY idproject
Yes the order of selecting matters. For performance reasons you (typically) want your most limiting select first to narrow your data set. This makes every subsequent query operate on a smaller dataset.

SQL GROUP BY/COUNT even if no results

I am attempting to get the information from one table (games) and count the entries in another table (tickets) that correspond to each entry in the first. I want each entry in the first table to be returned even if there aren't any entries in the second. My query is as follows:
SELECT g.*, count(*)
FROM games g, tickets t
WHERE (t.game_number = g.game_number
OR NOT EXISTS (SELECT * FROM tickets t2 WHERE t2.game_number=g.game_number))
GROUP BY t.game_number;
What am I doing wrong?
You need to do a left-join:
SELECT g.Game_Number, g.PutColumnsHere, count(t.Game_Number)
FROM games g
LEFT JOIN tickets t ON g.Game_Number = t.Game_Number
GROUP BY g.Game_Number, g.PutColumnsHere
Alternatively, I think this is a little clearer with a correlated subquery:
SELECT g.Game_Number, G.PutColumnsHere,
(SELECT COUNT(*) FROM Tickets T WHERE t.Game_Number = g.Game_Number) Tickets_Count
FROM Games g
Just make sure you check the query plan to confirm that the optimizer interprets this well.
You need to learn more about how to use joins in SQL:
SELECT g.*, count(*)
FROM games g
LEFT OUTER JOIN tickets t
USING (game_number)
GROUP BY g.game_number;
Note that unlike some database brands, MySQL permits you to list many columns in the select-list even if you only GROUP BY their primary key. As long as the columns in your select-list are functionally dependent on the GROUP BY column, the result is unambiguous.
Other brands of database (Microsoft, Firebird, etc.) give you an error if you list any columns in the select-list without including them in GROUP BY or in an aggregate function.
"FROM games g, tickets t" is the problem line. This performs an inner join. Any where clause can't add on to this. I think you want a LEFT OUTER JOIN.