Objective:
I wanted to show the number of distinct IDs for any combination selected.
In the below example, I have data at a granular level: ID level data.
I wanted to show the number of distinct IDs for each combination.
For this, I use count distinct which will give me '1' for the below combinations.
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in that case, if I just use this data, I would be showing the sum of E-comm and Face to face and the result would be '2' instead of '1'.
And this is not limited to Ecom/Face to face. I wanted to apply the same logic for all columns.
Please let me know if you have any other alternative approach to address this issue.
First aggregate in your table to get the distinct ids for each TranType:
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
and then join to the table:
SELECT t.*, g.counter_distinct
FROM tablename t
INNER JOIN (
SELECT TranType, COUNT(DISTINCT id) counter_distinct
FROM tablename
GROUP BY TranType
) g ON g.TranType = t.TranType
Or use a correlated subquery:
SELECT t1.*,
(SELECT COUNT(DISTINCT t2.id) FROM tablename t2 WHERE t2.TranType = t1.TranType) counter_distinct
FROM tablename t1
But let's say if I wanted to find the number of IDs who made both E-commerce and Face to face transactions, in
You can get the list of ids using:
select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2;
You can get the count using a subquery:
select count(*)
from (select id
from t
where tran_type in ('Ecomm', 'Face to face')
group by id
having count(distinct tran_type) = 2
) i;
Related
What I'm trying to do is returning both my queried (and limited) results as well as the total number of items in the table. Here's what I have so far.
SELECT id, name
FROM ??
WHERE
user_id = ?
LIMIT ? , ?;
SELECT COUNT(*) as total
FROM ??
WHERE
user_id = ?
;
This is two SQL queries and I was wondering how or if it's possible to combine it into one. I'd like the total to be by itself (if possible), otherwise as an attached column to each row. Or maybe what I have now is the most optimal solution.
Well, you could include the count in each row using a subquery:
SELECT
id,
name,
(SELECT COUNT(*) FROM yourTable WHERE user_id = ?) total
FROM yourTable
WHERE
user_id = ?;
But, from a separations of concerns point of view, this is probably not best practice. Instead, more typically I would expect to see two separate queries here.
SELECT SQL_CALC_FOUND_ROWS
...
LIMIT ...
SELECT FOUND_ROWS();
Reference.
Or, I would vote for the CROSS JOIN, not the subquery.
Another way to do the same using CROSS JOIN
SELECT
t1.id,
t1.[name],
t2.cnt
FROM
yourtable t1
CROSS JOIN
(
SELECT
COUNT(1) AS cnt
FROM
yourtable
WHERE
[user_id] = ?
) t2
WHERE
t1.[user_id] = ?
LIMIT
?, ?
i am using MySql workbench 5.7 to run this.
i am trying to get the result of this query:
SELECT COUNT(Users) FROM UserList.custumers;
and this query:
SELECT Users FROM UserList.custumers;
at the same table, meaning i want a list of users in one column and the amount of total users in the other column.
when i tries this:
SELECT Users , COUNT(Users) FROM UserList.custumers;
i get a single row with the right count but only the first user in my list....
You can either use a cross join since you know the count query will result in one row... whose value you want repeated on every row.
SELECt users, userCount
FROM userlist.custumers
CROSS JOIN (Select count(*) UserCount from userlist.custumers)
Or you can run a count in the select.... I prefer the first as the count only has to be done once.
SELECT users, (SELECT count(*) cnt FROM userlist.custumers) as userCount
FROM userlist.custumers
Or in a environment supporting window functions (not mySQL) you could count(*) over (partition by 1) as userCount
The reason you're getting one row is due to mySQL's extension of the GROUP BY which will pick a single value from non-aggregated columns to display when you use aggregation without a group by clause. If you add a group by to your select, you will not get the count of all users. Thus the need for the inline select or the cross join.
Consider: -- 1 record not all users
SELECT Users , COUNT(Users) FROM UserList.custumers;
vs --all users wrong count
SELECT Users , COUNT(Users) FROM UserList.custumers group by users;
vs -- what I believe you're after
SELECT Users, x.usercount FROM UserList.custumers
CROSS JOIN (Select count(*) UserCount from userlist.custumers) x
Use a subquery in SELECT.
Select Users,
(SELECT COUNT(Users) FROM UserList.custumers) as total
FROM UserList.custumers;
I have a MySQL table where I have a certain id as a foreign key coming from another table. This id is not unique to this table so I can have many records holding the same id.
I need to find out which ids are seen the least amount of times in this table and pull up a list containing them.
For example, if I have 5 records with id=1, 3 records with id=2 and 3 records with id=3, I want to pull up only ids 2 & 3. However, the data in the table changes quite often so I don't know what that minimum value is going to be at any given moment. The task is quite trivial if I use two queries but I'm trying to do it with just one. Here's what I have:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = MIN(SELECT COUNT(*) FROM table GROUP BY id)
If I substitute COUNT(*) = 3, then the results come up but using the query above gives me an error that MIN is not used properly. Any tips?
I would try with:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT COUNT(*) FROM table GROUP BY id ORDER BY COUNT(*) LIMIT 1);
This gets the minimum selecting the first row from the set of counts in ascendent order.
You need a double select in the having clause:
SELECT id
FROM table
GROUP BY id
HAVING COUNT(*) = (SELECT MIN(cnt) FROM (SELECT COUNT(*) as cnt FROM table GROUP BY id) t);
The MIN() aggregate function is suposed to take a column, not a query. So, I see two ways to solve this:
To properly write the subquery, or
To use temp variables
First alternative:
select id
from yourTable
group by id
having count(id) = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
)
Second alternative:
set #minCount = (
select min(c) from (
select count(*) as c from yourTable group by id
) as a
);
select id
from yourTable
group by id
having count(*) = #minCount;
You need to GROUP BY to produce a set of grouped values and additional select to get the MIN value from that group, only then you can match it against having
SELECT * FROM table GROUP BY id
HAVING COUNT(*) =
(SELECT MIN(X.CNT) AS M FROM(SELECT COUNT(*) CNT FROM table GROUP BY id) AS X)
I am trying to generate a simple report that will display the number of customers owning number of distinct brands. The following query I wrote generates the desired numbers one at a time. I tried writing a loop and it takes forever. Is there an alternative?
SELECT COUNT(DISTINCT customer_id)
FROM
(
SELECT customer_id,COUNT(DISTINCT brand) AS no_of_customers
FROM table_A
WHERE brand_id != 10
GROUP BY customer_id
HAVING COUNT(DISTINCT brand) =1
ORDER BY customer_id) as t1;
What this does is to give me a count of customers with a total count of distinct brands =1. I change the count of brands to 2,3 and so on. Please let me know if there is a way to automate this.
Thanks a lot.
Use a second level of GROUP BY to get them all in one query, rather than looping.
SELECT no_of_brands, COUNT(*) no_of_customers
FROM (SELECT customer_id, COUNT(DISTINCT brand) no_of_brands
FROM Table_A
WHERE brand_id != 10
GROUP BY customer_id) x
GROUP BY no_of_brands
You also don't need DISTINCT in your outer query, since the inner query's grouping guarantees that the customer IDs will be distinct.
Semi-newbyism ahead: I need to do two selects and count the number of items in both of them. Here's a bad example of what I thought would work --
sum(
select count(*) as count1 from users where name = 'John'
union
select count(*) as count1 from users where name = 'Mary'
) as theCount
(This is, as I said, a BAD example, since I could obviously write this as a single select with an appropriate WHERE clause. In what I really have to do, the two things I have to do are such that I can't do them as a single select (or, at least, I haven't yet found a way to do them as a single select).
Anyway, I think what I'm trying to do is clear: the select-union-select bit returns a column containing the counts of the two selects; that part works fine. I thought that wrapping them in a SUM() would get me what I wanted, but it's throwing a syntax error. The right thing is probably trivial, but I just don't see it. Any thoughts out there? Thanks!
For generic selects that you can't necessarily write with one where:
SELECT sum(count1) as totalcount FROM (
select count(*) as count1 from users where name = 'John'
union all
select count(*) as count1 from users where name = 'Mary'
) as theCount
select count(*) as count1 from users where name in ('John','Mary')
This is another alternative
select ( select count(*) as count1 from users where name = 'John')
+
( select count(*) as count1 from users where name = 'Mary') as total
Another possible solution:
select
sum(if(name='John',1,0)) as tot_John,
sum(if(name='Mary',1,0)) as tot_Mary,
sum(if(name in ('John','Mary'),1,0)) as total
from users