How to find the count of another group in a group - sql-server

I could not explain the problem clearly in the header but here is the issue.
I am using SQL Server.
I have a table that has Universities and Subjects.
University Subject
Melbourne Math
Melbourne Physics
Melbourne English
Ottawa Physics
Ottawa English
Ottawa Arts
Ottawa Computer
Sydney Math
Sydney Medicine
Sydney English
Sydney Computer
.
.
.
I want to do some calculations in one select statement
Here is my SQL
SELECT Subject, Count(*) SubjectsCount
FROM Table
GROUP BY Subject
Gives
Subject SubjectsCount
Math 39
Physics 23
English 47
Medicine 13
I want to fnd number of distinct Universities in the same query
Subject SubjectsCount UniversitiesNo
Math 39 52
Physics 23 52
English 47 52
Medicine 13 52
I tried this
SELECT Subject, Count(*) SubjectsCount, Count(*) OVER() AS UniversitiesNo
FROM Table
GROUP BY Subject
but this gave all records count
How can I specify for Universities distinct only?

You can CROSS JOIN a query that returns the number of all distinct universities:
SELECT t.Subject,
COUNT(*) SubjectsCount,
u.UniversitiesNo
FROM tablename t
CROSS JOIN (SELECT COUNT(DISTINCT University) UniversitiesNo FROM tablename) u
GROUP BY t.Subject, u.UniversitiesNo
Or even simpler:
SELECT Subject,
COUNT(*) SubjectsCount,
(SELECT COUNT(DISTINCT University) FROM tablename) UniversitiesNo
FROM tablename
GROUP BY Subject
See the demo.

Use COUNT DISTINCT:
SELECT Subject
, Count(*) SubjectsCount
, Count(DISTINCT University) AS UniversitiesNo
FROM Table
GROUP BY Subject
This query gives the number of distinct universites per Subject.
To get distinct number of universities simply CROSS JOIN:
SELECT t1.Subject,
t1.SubjectsCount,
t2.cnt
FROM (
SELECT Subject, Count(*) SubjectsCount
FROM Table1
GROUP BY Subject
) AS t1
CROSS JOIN (SELECT COUNT(DISTINCT University) FROM Table1) AS t2(cnt)
Demo here

Related

SQL: Compare two result from two different selects

I need to determine if our consultents are logging their work correctly. For that I have two different sources: one containing incoming calls and one their logs in our customer system.
Calls are linked to phone numbers and logs are linked to customer numbers. For each of the two sources I have a select that gives me the numbers of distinct combinations of weeknumber and (customer/phone)-numbers for each consultant to find total unique "weekcalls" for a full year. But how do I divide the results of unique logs with the unique calls? And for bonus difficulty, no temp tabels (doesn´t work in Excel)
Select #1
SELECT
count(distinct(concat(datepart(ww,call_datetime),phonenumber))) as
calls,consultant
FROM calltabel
group by consultant
Select #2
SELECT
count(distinct(concat(datepart(ww,log_datetime),phonenumber))) as
logs,consultant
FROM logtabel
group by consultant
results
select #1
consultant calls
eric 10
kimmie 20
select #2
consultant logs
eric 5
kimmie 20
The combined result should be
consultat calls logs result
eric 10 5 0.5
kimmie 20 20 1.0
You can join the queries like this
select t1.consultant, calls, logs, logs/calls as result
(SELECT
count(distinct(concat(datepart(ww,call_datetime),phonenumber))) as
calls,consultant
FROM calltabel
group by consultant) as t1
inner join
(SELECT
count(distinct(concat(datepart(ww,log_datetime),phonenumber))) as
logs,consultant
FROM logtabel
group by consultant) as t2 on t1.consultant=t2.consultant
Or you can do this:
select t1.consultant, calls, logs, logs/calls as result from
(
SELECT calltabel.consultant,
count(distinct(concat(datepart(ww,call_datetime),phonenumber))) as calls,
count(distinct(concat(datepart(ww,log_datetime),phonenumber))) as logs
FROM calltabel
inner join logtabel on logtabel.consultant= calltabel.consultant
group by calltabel.consultant
)
You can do inner join:
Select callTable.Consultant, callTable.calls, logTable.logs, logTable.logs/callTable.logs as ‘Result’ from (SELECT
count(distinct(concat(datepart(ww,call_datetime),phonenumber))) as
calls,consultant
FROM calltable
group by consultant) as callTable, (SELECT
count(distinct(concat(datepart(ww,log_datetime),phonenumber))) as
logs,consultant
FROM logtable
group by consultant) as logTable
Where logTable.consultant = callTable.consultant;

List customers who sold most in mssql

I'm new to sql.
I have to select top 3 companies who have the highest sells
Company Table:
CompanyId, Compnayname,etc
Orders Table:
OrderId, companyId,price,etc
select top 3 companyname , (select sum(price) from ordes) as Maximum from company order by Maximum Desc?
I think i need to join these but i cant find a way around it
Join these tables, group by company's name and order by their total sales:
select top 3 c.Companyname, sum(o.price) as TotalSales
from Orders o
inner join Company c on c.CompanyId = o.companyid
group by c.Companyname
order by TotalSales desc

nested group by select in SQL Server

I am doing the following SELECT statement to see how many Reps each of my Manufacturers have in my database, this is working nicely:
SELECT ManufacturerId, COUNT(*) AS RepCount
FROM ManufacturerSalesReps WHERE IsDeleted=0
GROUP BY ManufacturerID
ORDER BY COUNT(*)
So this gives me the ManufacturerId and the number of reps but what i really need is the number of manufacturers at different rep counts. So I want to GROUP the results from the above SELECT by RepCount.
How do I accomplish this?
I cannot think of something else, but:
SELECT T.RepCount, COUNT(*) AS ManufacturerCount
FROM (
SELECT ManufacturerId, COUNT(*) AS RepCount
FROM ManufacturerSalesReps
WHERE IsDeleted=0
GROUP BY ManufacturerID
) AS T
GROUP BY T.RepCount
ORDER BY COUNT(*)
Either this is correct or totally dumb.
With windowing functions
SELECT ManufacturerId, COUNT(*),
count(ManufacturerId) over (partition by COUNT(*)) num_man AS RepCount
FROM ManufacturerSalesReps WHERE IsDeleted=0
GROUP BY ManufacturerID
ORDER BY 2

Using SELECT TOP from one column, then sorting on a different column

I'm using SQL Server 2005, and I want to query for the vendors generating the most revenue, sorted by the vendor's name. Below is the query I have tried. The inner subquery gets the 15 largest vendors sorted by revenue, and I try to order those results by the vendor name.
SELECT Revenue, VendorName
FROM (
SELECT TOP 15
SUM(po.POTotal) AS Revenue
, Vendors.VendorName AS VendorName
FROM PurchaseOrders po
INNER JOIN Vendors ON po.Vendor_ID = Vendors.Vendor_ID
WHERE ...
GROUP BY Vendors.VendorName
ORDER BY Revenue DESC
)
ORDER BY VendorName ASC
But this gives me an error message:
Msg 156, Level 15, State 1, Line 14
Incorrect syntax near the keyword 'ORDER'.
Is there another way to do this? I think this might be possible with a view, but I'd prefer not to do it that way.
I apologize if this is a duplicate, I don't even know what to search for to see if this has already been asked.
Add an alias for the subquery:
SELECT Revenue, VendorName
FROM (SELECT TOP 15
SUM(po.POTotal) AS Revenue,
v.VendorName AS VendorName
FROM PurchaseOrders po
JOIN Vendors v
ON po.Vendor_ID = v.Vendor_ID
WHERE ...
GROUP BY v.VendorName
ORDER BY Revenue DESC) Z
ORDER BY VendorName ASC
You need to give your derived table an alias:
...
ORDER BY Revenue DESC
) AS DerivedTable
ORDER BY VendorName;
I believe you can do this with a CTE:
WITH revenue (Revenue, VendorName)
AS
(SELECT TOP 15 SUM(po.POTotal) AS Revenue, Vendors.VendorName AS VendorName
FROM PurchaseOrders po
INNER JOIN Vendors
ON po.Vendor_ID = Vendors.Vendor_ID
WHERE ...
GROUP BY Vendors.VendorName
ORDER BY Revenue DESC)
SELECT Revenue, VendorName
FROM revenue
ORDER BY VendorName ASC
You can also do this without a sub-query if you like --
SELECT sum(po.POTotal) as Revenue, vendors.VendorName
FROM PurchaseOrders po INNER JOIN Vendors ON po.Vendor_ID = Vendors.Vendor_ID
WHERE ...
GROUP BY Vendors.VendorName
ORDER BY sum(po.POTotal) DESC, VendorName ASC
Try that and see if it works - we do the same sort of thing here and this was our solution...
Sorry, forgot the TOP 15 in the query above - it needs to go just befor the sum() aggregate function.

SQL Server query - find first in sequence

Let's say I have the following example table
GroupID ItemID Created
-----------------------------------------------
A ABC 5/1/2009 13:02
A XZY 5/1/2009 13:01
A LMO 5/1/2009 13:03
A DEF 5/1/2009 13:00
A PQR 5/1/2009 13:04
B WXY 5/1/2009 13:02
B HIJ 5/1/2009 13:03
B STU 5/1/2009 13:01
How can I return the first ItemID for each group based on the Created column? I need a query to return the following:
GroupID ItemID Created
-----------------------------------------------
A DEF 5/1/2009 13:00
B STU 5/1/2009 13:01
The data set I'm working with may have several thousand to a few million rows, so I'd like to avoid any costly subqueries if possible. I was thinking maybe I could do it with an inner join, but my initial attempts led to my own confusion.
Edit: So far, I have the following:
select t2.ItemID, count(*) from
(select GroupID, min(created) as created from table) t1
inner join table t2 on t1.created = t2.created
group by t2.itemid
Any reason this isn't going to work? It's slower than I'd like, but it's updating a summary table, so it's not a huge issue.
SELECT myTable.*
FROM myTable
INNER JOIN (
SELECT GroupID, Min(Created) AS MinCreated
FROM myTable) AS SummarizedTable
ON myTable.GroupID = SummarizedTable.GroupID
WHERE myTable.Created = SummarizedTable.MinCreated
Note: Done without help of query analyzer. So, please be kind :)
No inner joins needed. Classic PARTITION BY problem.
Not tested but this should put you on the right track.
SELECT RowNumber() OVER(PARTITION BY GroupID ORDER BY Created ASC) AS RowNum, *
FROM YourTable
Depends on the SQL Server version but 2005 onwards have the ranking functions which can simplify it
Select GroupID, ItemID, Created
FROM
(
select GroupID, ItemID, Created, DENSE_RANK ( ) OVER ( partition by GroupID
order by Created asc) as Rank
from yourTable
) as A
where Rank = 1
One note though, is that if 2 record tie, it would return both, this might be advantageous, or a pain depending on what you needed, it can be dropped to one using select distinct.
select m1.Groupid, m1.itemid, m1.created
from mytable m1
join
(select groupid,min(created) as created from mytable) m2
on m1.groupid = m2.group_id and m1.created = m2.created

Resources