How do I perform MAX(COUNT(*)) query? - sql-server

I have a database where I have MenuItem, Item, Item_Details, and Item_Category tables. I would like to get an Item which is most frequently used in Menu.
SELECT
ItemName,
Category,
ItemPrice
FROM
restuarant.Menu_Item,
restuarant.Item,
restuarant.Item_Details,
restuarant.Item_Type
WHERE ItemId = Id_Item
AND ItemTypeId = Id_ItemType
AND ItemDetailsId = Id_ItemDetails
AND ItemId =
(SELECT ItemId
FROM restuarant.Menu_Item
HAVING COUNT(ItemId) =
(SELECT MAX(COUNT(ItemId))
FROM restuarant.Menu_Item
GROUP BY Id_MenuItem);
So the problems is I'm performing my subqueries incorrectly, I'm getting an error 'Cannot perform an aggregate function on an expression containing an aggregate or a subquery.'

How about the following:
SELECT TOP (1) ItemId, COUNT(ItemId) AS MCOUNT
FROM Menu_Item
GROUP BY ItemId
ORDER BY COUNT(ItemId) DESC

Example 1:
select aic.County, count(*) from Address_Information_County aic
group by aic.County
having count(*) = (select top 1 count(*) from Address_Information_County group by County order by count(*) desc);
Example 2:
select aic.County, count(*) from Address_Information_County aic
group by aic.County
having count(*) = (select max(cnt) from (select count(*) cnt from Address_Information_County group by County) x);

You could use "Group By" aggregate function to achieve this.
SELECT ItemID, count(*) as cnt
FROM restaurant r
GROUP BY r.ItemID
ORDER BY cnt desc
LIMIT 1;
In case, there are multiple entries that have count same as MaxCount, the following query would work.
SELECT ItemID, count(*) as cnt
FROM restaurant r
GROUP BY r.ItemID
HAVING count(*) =
(
SELECT count(*) as max_cnt
FROM restaurant r2
GROUP BY r2.ItemID
ORDER BY max_cnt desc
LIMIT 1
)
;

Related

MSSQL Union All two queries with if statement

I have a query the following works as expected
If((Select count(*) from table1 where product = 'carrot')< 5)
Begin
Select Top (5 - (Select count(*) from table1 where product = 'carrot'))
id, product From table2
WHere id NOT IN
(Select id from table1) AND product = 'carrot'
Order by newid()
END
What i want to do is Union or Union all say another product potatoes
If((Select count(*) from table1 where product = 'potato')< 5)
Begin
Select Top (5 - (Select count(*) from table1 where product = 'potato'))
id, product From table2
WHere id NOT IN
(Select id from table1) AND product = 'potato'
Order by newid()
END
I keep getting a syntax error, when i add UNION between IF or after END. Is this possible or another way is better....
What i am doing is trying to select a random sample of carrots, first i want to check if i have the 5 carrots in table1. if i do don't run sample.
If i do not have 5 total carrots run the sampler and return 5 carrots. I then filter out if they already exist in table 1 by the id. Then it subtracts the count from the new sample for a total of five.
It works well, now i want to run for other products eg lettuce, potatoes etc...
But i want an UNION or UNION All. hope makes sense.
I'd be interested to see whether this way works-
Select Top (5 - (Select count(*) from table1 where product = 'carrots')< 5)
id
, product
From table2
WHere id NOT IN (Select id from table2)
AND (Select count(*) from table1 where product = 'carrots')< 5)
UNION ALL
Select Top (5 - (Select count(*) from table1 where product = 'potatoes')< 5)
id
, product
From table2
WHere id NOT IN (Select id from table2)
AND (Select count(*) from table1 where product = 'potatoes')< 5)
Your style is interesting, feels procedural rather than set-based.
You can try it this way
If(((Select count(*) from table1 where product = 'carrot'< 5) and (Select count(*) from table1 where product ='potato' <5))
)
Begin
Select Top (5 - (Select count(*) from table1 where product = 'carrot')) id, product
From table2
WHere id NOT IN (Select id from table1) AND product = 'carrot' Order by newid()
Union all
Select Top (5 - (Select count(*) from table1 where product = 'potato')) id, product From table2
WHere id NOT IN (Select id from table1) AND product = 'potato' Order by newid()
END
IF statements in SQL do not behave as sub-queries or row-sets in SQL, as you've found out. They are for branching the flow of control only.
Here is a more set based approach you could take:
SELECT ProdSamples.*
FROM
(
SELECT Table2.*, ROW_NUMBER() OVER (PARTITION BY table2.Product ORDER BY NEWID()) RowNum
FROM Table2
LEFT JOIN Table1
ON Table1.id = Table2.id
WHERE Table1.id IS NULL
) ProdSamples
JOIN
(
SELECT Product, COUNT(*) ProdCount
FROM Table1
GROUP BY Product
) ProdCounts
ON ProdSamples.Product = ProdCounts.Product
AND ProdSamples.RowNum <= (5 - ProdCounts.ProdCount)
The first sub-query ProdSamples returns all the products from Table2 that do not have an id in Table1. The RowNum field ranks them in random order partitioned by Product.
The second sub-query ProdCounts is the count of records for each product in Table1. Then it joins these sub-queries together and only returns the records from ProdSamples where the RowNum is lower or equal to the number of samples you want to return.

Select highest value in a column with other column values SQL Server

My table looks like this:
And I want to get highest bid amount for a specific product, with the row id. My query is like this
SELECT
MAX(BidAmount) as highestBid,id
FROM
[wf_bid]
WHERE
ProductId = 101 AND ClientId = 101
GROUP BY
id
I expect only one row with highest BidAmount, but the query returns all rows with this product id and client id. How can I fix this issue?
How about sub-query ? If you have multiple records with same BidAmount, then it return top 1.
SELECT TOP 1
BidAmount as highestBid,id
FROM [wf_bid] WHERE BidAmount = (Select Max(BidAmount) FROM [wf_bid] WHERE ProductId=101 and ClientId=101)
You can use row_number() and select the first row:
SELECT *
FROM
(
SELECT
id,
BidAmount,
ROW_NUMBER() OVER (ORDER BY BidAmount desc) as rn
FROM
[wf_bid]
WHERE ProductId = 101 and ClientId = 101
) i
WHERE
i.rn = 1
How about this way:
SELECT id,highestBid from
(Select Max(BidAmount)highestBid,productID,clientid FROM [wf_bid] WHERE ProductId=101 and ClientId=101) a
LEFT JOIN
(SELECT id,productID,clientid FROM [wf_bid]) as b
where a.productID = b.productid and a.clientid = b.clientid
try this way,
select * FROM
(SELECT
id,
BidAmount,
ROW_NUMBER() OVER (parrtition by ProductId ORDER BY BidAmount desc) as rn
FROM
[wf_bid]
WHERE ClientId = 101)t4
where rn=1
Your problem is in the group by ID, it doesn't work that way because it isn't "adding your bids" it is telling you the max number of every ID not just which is the biggest bid and it's ID. I'm guessing you'll get what you want if you delete group by id. If not you would need to explain your need further.

How to find duplicate rows where 4 colums are matching and 3 are not

I have table with the following schema
TransNo|TransId|createddate|order|tank|meter|quantity
We have different values for 1st 3 columns, but the next 4 are same.
I want to get TransNo where the last four (order, tank, meter and quantity) are same to delete duplicates if they exist.
To only find TransNo with duplicate 'last four':
WITH cte AS (
SELECT TransNo, COUNT(*) OVER (PARTITION BY [order],tank,meter,quantity) cnt
FROM your_table
)
SELECT TransNo
FROM cte
WHERE cnt>1
To delete rows with the same 'last four' and TransNo > min(TransNo) for this 'last four':
WITH cte AS (
SELECT ROW_NUMBER() OVER (PARTITION BY [order],tank,meter,quantity ORDER BY TransNo) AS rn
FROM your_table)
DELETE FROM cte
WHERE rn>1
You can have a try with below query.
SELECT *
FROM ABC
WHERE order1 IN (SELECT order1
FROM order1 GROUP BY
order1
HAVING COUNT(TransNo) > 1)
AND
tank IN (SELECT tank
FROM tank
GROUP BY tank
HAVING COUNT(TransNo) > 1)
AND
meter IN (SELECT meter
FROM meter
GROUP BY meter
HAVING COUNT(TransNo) > 1)
AND
quantity IN (SELECT quantity
FROM quantity
GROUP BY quantity
HAVING COUNT(TransNo) > 1)
You can SELECT duplicate values by using GROUP BY into a temp-table and then use that result to aggregate TransNo:
SELECT [order], tank, meter, quantity
INTO #duplicates
FROM <your table>
GROUP BY [order], tank, meter, quantity
HAVING COUNT(*) > 1
SELECT DISTINCT b.TransNo, c.TransNo --Optional: , b.[order], b.tank, b.meter, b.quantity
FROM #duplicates a
INNER JOIN <your table> b ON
AND a.[order] = b.[order]
AND a.tank = b.tank
AND a.meter = b.meter
AND a.quantity = b.quantity
INNER JOIN <your table> c ON
AND a.[order] = c.[order]
AND a.tank = c.tank
AND a.meter = c.meter
AND a.quantity = c.quantity
AND b.TransNo <> c.TransNo

Select Multiple Columns join SQL Server

I have an Employee table like this
And a second table for EmployeeComments with the EmployeeID as foreign key:
I would like to query the employees with their comments in the following format:
select Name, Comment
from Employee emp
left join EmployeeComments empC on empC.EmployeeID = emp.ID
I would like the results to be like:
I have already looked at Pivot, but it doesn't resolve my issue
Use window function:
select case when row_number() over(partition by emp.name order by empC.ID) = 1
then Name
else '' end as Name,
Comment
from Employee emp
left join EmployeeComments empC On empC.EmployeeID = emp.ID
This might give you some kind of order in your result window at least
WITH cte AS(
SELECT emp.Name ,
empC.Comment,
RANK() OVER (ORDER BY emp.Name) NameOrder,
ROW_NUMBER() OVER (PARTITION BY emp.Name ORDER BY empC.ID) RN
FROM Employee emp
LEFT JOIN EmployeeComments empC ON empC.EmployeeID = emp.ID
)
SELECT
Name = (CASE WHEN RN = 1 THEN Name ELSE '' END),
Comment
FROM
cte
ORDER BY
NameOrder,
RN
"use Cross Join:"
Query:
select case t.cnt
when 1 then
coalesce(t.Name,' ')
end as Name,t.comment
from
(
select t1.Name,t2.comment,row_number()
over(partition by t1.name order by t1.Name)
as cnt
from
EmployeeComments t1
cross join
Employee t2
where t1.ID=t2.Employeeid
)t

select top 1 with a group by

I have two columns:
namecode name
050125 chris
050125 tof
050125 tof
050130 chris
050131 tof
I want to group by namecode, and return only the name with the most number of occurrences. In this instance, the result would be
050125 tof
050130 chris
050131 tof
This is with SQL Server 2000
I usually use ROW_NUMBER() to achieve this. Not sure how it performs against various data sets, but we haven't had any performance issues as a result of using ROW_NUMBER.
The PARTITION BY clause specifies which value to "group" the row numbers by, and the ORDER BY clause specifies how the records within each "group" should be sorted. So partition the data set by NameCode, and get all records with a Row Number of 1 (that is, the first record in each partition, ordered by the ORDER BY clause).
SELECT
i.NameCode,
i.Name
FROM
(
SELECT
RowNumber = ROW_NUMBER() OVER (PARTITION BY t.NameCode ORDER BY t.Name),
t.NameCode,
t.Name
FROM
MyTable t
) i
WHERE
i.RowNumber = 1;
select distinct namecode
, (
select top 1 name from
(
select namecode, name, count(*)
from myTable i
where i.namecode = o.namecode
group by namecode, name
order by count(*) desc
) x
) as name
from myTable o
SELECT max_table.namecode, count_table2.name
FROM
(SELECT namecode, MAX(count_name) AS max_count
FROM
(SELECT namecode, name, COUNT(name) AS count_name
FROM mytable
GROUP BY namecode, name) AS count_table1
GROUP BY namecode) AS max_table
INNER JOIN
(SELECT namecode, COUNT(name) AS count_name, name
FROM mytable
GROUP BY namecode, name) count_table2
ON max_table.namecode = count_table2.namecode AND
count_table2.count_name = max_table.max_count
I did not try but this should work,
select top 1 t2.* from (
select namecode, count(*) count from temp
group by namecode) t1 join temp t2 on t1.namecode = t2.namecode
order by t1.count desc
Here are to examples that you could use but the temp table use is more efficient than the view, but was done on a small data sample. You would want to check your own statistics.
--Creating A View
GO
CREATE VIEW StateStoreSales AS
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank'
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
GO
SELECT * FROM StateStoreSales
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP VIEW StateStoreSales
---Using a Temp Table
SELECT t.state,t.stor_id,t.stor_name,SUM(s.qty) 'TotalSales'
,ROW_NUMBER() OVER (PARTITION BY t.state ORDER BY SUM(s.qty) DESC) AS 'Rank' INTO #TEMP
FROM [dbo].[sales] s
JOIN [dbo].[stores] t ON (s.stor_id = t.stor_id)
GROUP BY t.state,t.stor_id,t.stor_name
SELECT * FROM #TEMP
WHERE Rank <= 1
ORDER BY TotalSales Desc
DROP TABLE #TEMP

Resources