I have a simple table arranged as below and I'd like to write a query that returns the single client_id that has most transactions. One client has most transactions than any other client in the table.
transaction_id int
client_id int
comments varchar
Cheers.
Here is one method for obtaining the data by counting the rows, grouping on the client_id and then filtering for top 1 ordered by the count descending.
declare #table table (
transaction_id int,
client_id int,
comments varchar(20)
);
insert into #table (transaction_id, client_id, comments)
values
(1, 1, ''),
(2, 2, ''),
(3, 2, ''),
(4, 3, '')
select top 1 client_id, count(*) as vol
from #table
group by client_id
order by vol desc
This will do it for you:
SELECT client_id FROM table_name GROUP BY client_id ORDER BY COUNT(*) DESC limit 1;
select client_id, count(transaction_id)
from table
group by client_id
order by 2 desc
limit 1;
Group by helps to gather records based on a particular column and the countreturns the number of records corresponding to that column value. Order by desc arranges in descending order and limit 1 restricts to 1 record.
Related
I am relatively new to SQL and I am trying to extract rows where they have the highest values.
For example, the table look like this:
user_id fruits
1 apple
1 orange
2 apple
1 pear
I would like to extract the data such that it would look like this:
user_id fruits
1 3
If user_id 2 has 3 fruits, it should display:
user_id fruits
1 3
2 3
I can only manage to get the if I use LIMIT = 1 by DESC order, but that is not the right way to do it. Otherwise I am getting only:
user_id fruits
1 3
2 1
Not sure where to store the max value to put in the where clause. Appreciate any help, thank you
Use RANK():
WITH cte AS (
SELECT user_id, COUNT(*) AS cnt, RANK() OVER (ORDER BY COUNT(*) DESC) rnk
FROM yourTable
GROUP BY user_id
)
SELECT user_id, cnt AS fruits
FROM cte
WHERE rnk = 1;
Here's one answer (with sample data):
CREATE TABLE something (user_id INT NOT NULL, fruits VARCHAR(10) NOT NULL, PRIMARY KEY (user_id, fruits));
INSERT INTO something VALUES (1, 'apple');
INSERT INTO something VALUES (1, 'orange');
INSERT INTO something VALUES (2, 'apple');
INSERT INTO something VALUES (1, 'pear');
INSERT INTO something VALUES (2, 'orange');
INSERT INTO something VALUES (2, 'pear');
SELECT user_id, COUNT(*) AS cnt
FROM something
GROUP BY user_id
HAVING COUNT(*) >= ALL (SELECT COUNT(*) FROM something GROUP BY user_id);
fbn table:
create table fbn (
id int,
name varchar(40),
birthday date,
gender varchar(10));
INSERT into fbn values
(1, "James", "2000-04-22", "male"),
(2, "Julia", "2006-02-27", "female"),
(3, "Ethan", "2013-05-23", "male"),
(4, "Lion", "2014-09-11", "male"),
(5, "Ethan", "2006-01-01", "male"),
(6, "Lion", "2006-02-01", "male");
what's the name that occur most? note that there are two names (Ethan and Lion) occur most often. I have two solutions as below:
select tmp2.name
from (select tmp.name,
dense_rank() over(order by tmp.name_count desc) rank
from (select name,
count(*) name_count
from fbn
group by name) tmp
) tmp2
where tmp2.rank = 1;
and the 2nd solution:
select name from fbn
group by name
having count(name) = (select count(name) from fbn
group by name
order by count(name) desc
limit 1);
both seem to be working, but both looks like too complicated. is there any other solution that's more concise easier to understand? Thanks
How about this:
SELECT counts,GROUP_CONCAT(NAME) AS names
FROM
(SELECT NAME, COUNT(*) counts FROM fbn GROUP BY NAME) A
GROUP BY counts
ORDER BY counts DESC
LIMIT 1;
Fiddle here : https://www.db-fiddle.com/f/qzmJAx5LFfzZdYyDetUfex/1
I think you can simply:
select count(id) as num_names, name from fbn group by name order by num_names desc limit 1;
For Ms :
select Top 1 count(id) as num_names, name from fbn group by name order by num_names desc
Disable ONLY_FULL_GROUP_BY if its enabled using:
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
Here in inner query provide name with occurrence count. And outer query just use that temporary table to get max count value. Now it will return single row with name & total occurrence(max).
SELECT name, MAX(occurrence)
FROM (SELECT name, COUNT(id) occurrence
FROM fbn
GROUP BY name) t;
Help me understand the following snippet:
...
ORDER BY 2, 12, 11
In SQL ORDER BY is the Keyword used to Order your Resultset based on the values of a Particular column or Columns either Ascending or Descending order.
The ORDER BY is Given as the Last Statement in a SELECT.
The Syntax is :
SELECT
<List of Columns>
FROM <Table Name>
<Filter Conditions > -- Optional
<Group By and Having> - Optional
ORDER BY
<Column 1> <ASC or DESC>,
<Column 2> <ASC or DESC>,
.......
<Column N> <ASC or DESC>,
You Can Either Give the Column Names or the Ordinal Position of the Column in the Select List.
For Example :
SELECT
EmpId,
FirstName,
LastName,
Age,
ContactNumber
FROM Employee
ORDER BY
FirstName,
Age
Can Also be written as
SELECT
EmpId,
FirstName,
LastName,
Age,
ContactNumber
FROM Employee
ORDER BY
2,4
in the second one, I'm giving the Ordinal position of Columns FirstName and Age instead of specifying the Column Name.
This approach is more useful when you have 2 columns with the Same Name in your Resultset.
Example :
SELECT
EmpId,
*
ContactNumber
FROM Employee
ORDER BY
EmpId
The above will give you the following error
Msg 209, Level 16, State 1, Line 5 Ambiguous column name 'EmpId'.
So Instead you can say
SELECT
EmpId,
*
ContactNumber
FROM Employee
ORDER BY
1
You can get and learn in details from the below query. Multiple column OrderBy is useful when similar values are present in table.
Create Table Orders (Id int, ProdName Varchar(20))
insert into Orders Values (1, 'A'), (4, 'C'), (2, 'B'), (3, 'E'), (4, 'G'), (5, 'D'), (6, 'F'), (7, 'G')
Select * from Orders
order by 1 -- Order By Id Ascending
Select * from Orders
order by 1 desc -- Order By Id Descending
Select * from Orders
order by 2 -- Order By Name Ascending
Select * from Orders
order by 2 desc -- Order By Name Descending
Select * from Orders
order by 1, 2 -- Order By Id first and then Name Ascending.
-- It will come same Id first and same name later
Select * from Orders
order by 1 asc, 2 desc --First priority of Id ascending then Name in descending order
Select * from Orders
order by 1, 2 desc
You can find the live demo Live Demo Here
I have a table that holds relations of users participating in conversations like follows:
CREATE TABLE `so` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`user_id` int(11) NOT NULL,
`conversation_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `so`
ADD UNIQUE KEY `uc` (`user_id`,`conversation_id`) USING BTREE;
INSERT INTO `so` (`id`, `user_id`, `conversation_id`) VALUES
(1, 1, 1),
(3, 1, 2),
(2, 2, 1),
(4, 2, 2),
(5, 3, 2);
According to sample data, users 1 and 2 have conversation with ID of 1 and users 1, 2, 3 - conversation with ID of 2.
I need to get unique conversation_id for the list of user ids.
My current query is:
SELECT conversation_id, COUNT(user_id) as usersCount
FROM so
WHERE user_id IN (1,2)
GROUP BY conversation_id
HAVING usersCount = 2
ORDER BY NULL
But it returns 2 rows for both conversations and I expect the row with conversation_id of 1.
How can I select the row that belongs exactly to users 1 and 2, and not to 1, 2, 3? Thanks.
UPDATE:
I can't use subqueries on joins for performance reasons because users list in the query may be up to 30 ids and I'm afraid 30 subqueries is not the case.
You can use group_concat
select conversation_id
from so
group by conversation_id
having group_concat(user_id order by user_id) = '1,2';
To avoid full index scan, you can put your original query in a subquery:
SELECT a.conversation_id
FROM (
SELECT conversation_id
FROM so
WHERE user_id IN (1,2)
GROUP BY conversation_id
HAVING COUNT(conversation_id) = 2) a
JOIN so b ON a.conversation_id = b.conversation_id
GROUP BY a.conversation_id
HAVING COUNT(a.conversation_id) = 2;
Instead of checking the user_id in the WHERE clause, compare the number of rows that satisfy that condition with the total rows for each conversation.
SELECT conversation_id, COUNT(*) AS allCount, SUM(user_id IN (1, 2)) AS userCount
FROM so
GROUP BY conversation_id
HAVING allCount = 2 AND allCount = userCount
This answer is an alternative to the already given, and will provide better efficiency through not using sub-selects.
HAVING COUNT(user_id IN ('1','2') OR NULL) > 0 specifies that you want conversations with userid 1 and 2.
COUNT(user_id) = 2 says that there can only be 2 users in the conversation.
You could even remove COUNT(user_id) as usersCount from the result set if you don't actually use it as part of your exercise.
SELECT conversation_id, COUNT(user_id) as usersCount
FROM so
GROUP BY conversation_id
HAVING COUNT(user_id IN ('1','2') OR NULL) > 0 AND
COUNT(user_id) = 2;
To avoid a full index scan you would have to use a where clause as #Fabricator has shown in his answer. When you apply conditions to groups of rows, it has to group them first, and then do the aggregations and conditions, and a where clause only applies conditions to single rows. How big is your table out of interest?
Is it possible to select distinct company names from the customer table but also displaying the iD's related?
at the minute I'm using
SELECT company,id, COUNT(*) as count FROM customers GROUP BY company HAVING COUNT(*) > 1;
which returns
MyDuplicateCompany1 64 2
MyDuplicateCompany2 20 3
MyDuplicateCompany6 175 2
but what I'm after is all the duplicate ID's for each.
so
CompanyName, TimesDuplicated, DuplicateId1, DuplicateId2, DuplicateId3
or a row for each so
MyDuplicateCompany1, DuplicateId1, TimesDuplicated
MyDuplicateCompany1, DuplicateId2, TimesDuplicated
MyDuplicateCompany2, DuplicateId1, TimesDuplicated
MyDuplicateCompany2, DuplicateId2, TimesDuplicated
MyDuplicateCompany2, DuplicateId3, TimesDuplicated
is this possible?
Not sure if this would be acceptable but there's a function in mySQL which allows you to combine multiple rows into one Group_Concat(Field), but show the distinct values for each record for columns specified (like ID in this case)
SELECT company
, COUNT(*) as count
, group_concat(ID) as DupCompanyIDs
FROM customers
GROUP BY company
HAVING COUNT(*) > 1;
SQL Fiddle
showing similar results with duplicate companies listed in one field.
If you need it in multiple columns or multiple rows, you could wrap the above as an inline view and inner join it back to customers on the name to list the duplicates and times duplicated.
You can use GROUP_CONCAT(id) to concat your id by comma, your query should be:
SELECT company, GROUP_CONCAT(id) as ids, COUNT(id) as cant FROM customers GROUP BY company HAVING cant > 1
You can test the query with this
CREATE TABLE IF NOT EXISTS `customers` (
`id` int(11) NOT NULL,
`company` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `customers` (`id`, `company`) VALUES
(1, 'MyDuplicateCompany1'),
(2, 'MyDuplicateCompany1'),
(3, 'MyDuplicateCompany1'),
(4, 'MyDuplicateCompany2'),
(5, 'MyDuplicateCompany2'),
(6, 'MyDuplicateCompany3'),
(7, 'MyDuplicateCompany3'),
(8, 'MyDuplicateCompany3'),
(9, 'MyDuplicateCompany3'),
(10, 'MyDuplicateCompany4');
Output:
Read more at:
http://monksealsoftware.com/mysql-group_concat-and-postgres-array_agg/
You are not looking for companies with more than 1 entry (GROUP BY company), but for duplicate company IDs (GROUP BY company, id):
SELECT company, id, COUNT(*)
FROM customers
GROUP BY company, id
HAVING COUNT(*) > 1;
This should give exactly what you're looking for without GROUP_CONCAT()
SELECT
company, id,
( SELECT COUNT(*) from customers AS b
WHERE a.company = b.company
) AS cnt
FROM customers AS a
GROUP BY company, id
HAVING cnt > 1
;
Note: GROUP_CONCAT does the same thing, just all in one row per company.