Count companies with more than one contact - sql

Select count (distinct company_id)
from contacts
group by company_id
having count(contact_id) >1) from contact
I used this query but output comes with list of rows and their contact with more than 2.
I looking for single digit like 6 as output.

It depends on the fine print! You commented:
there are some company_id with null, and have contact_id on them, I don't want to use NULL
So we exclude company_id IS NULL. Still unclear how to deal with contact_id IS NULL. Some options:
SELECT count(*)
FROM (
SELECT count(*) AS ct -- count all contacts
-- count(contact_id) AS ct -- count not-null contacts
-- count(DISTINCT contact_id) AS ct -- count not-null, distinct contacts
FROM contacts
WHERE company_id IS NOT NULL -- "I dont want to use NULL"
GROUP BY company_id
) t
WHERE ct > 1;
A HAVING clause in the subquery is equivalent. WHERE in the outer query is just simpler syntax.

select count(*) from
(
select company_id
from contacts
where company_id is not null
group by company_id
having count(distinct contact_id) > 1
) t;
If you are sure that all (company_id, contact_id) pairs are unique then count(distinct contact_id) becomes simply count(*)

Related

Count on Table 1 based on Count with Clause on Table 2, sql

Table 1
Table 2
I need to find the Count of total number of unique stores that have "Achieved Date" not Null that achieved all of the "Achievement Ids" "enabled" on Table 2.
So far I can find the count of stores that achieved a hard coded number, but I'm not breaking through the part where I use the Count of Enabled Ids on table 2 to define what the number is.
SELECT
COUNT(*) AS count
FROM
(SELECT
StoreNumber, COUNT(*) as Achievements
FROM
StoreAchievementProgress
WHERE
AchievedDate IS NOT NULL
GROUP BY
StoreNumber) count
maybe this query
SELECT S.StoreNumber
FROM StoreAchievementProgress S
RIGHT JOIN (SELECT Id FROM Table2 WHERE Enabled=1 )T
ON T.Id=S.AchievementId
AND AchievedDate IS NOT NULL
GROUP BY S.StoreNumber
HAVING COUNT(1) = (SELECT COUNT(Id) FROM Table2 WHERE Enabled=1 )
Joining the stores with a count of their enabled achievements to how many they can get
SELECT COUNT(*) AS StoresFullAchievements
FROM
(
SELECT p.StoreNumber, COUNT(*) AS TotalEnabledAchievements
FROM StoreAchievementProgress p
JOIN Achievements a ON a.id = p.AchievementId
WHERE p.AchievedDate IS NOT NULL
AND a.Enabled = 1
GROUP BY p.StoreNumber
) AS s
JOIN
(
SELECT COUNT(*) AS TotalEnabled
FROM Achievements
WHERE Enabled = 1
) a
ON a.TotalEnabled = s.TotalEnabledAchievements

How do I get a count of records from one table with detail from another table

In Oracle I have two tables, USER and USER_DETAIL. The USER_DETAIL table has a foreign key link to the USER table, so pretty standard stuff. The USER table has among others USER_ID and ACCOUNT_NUM fields, and USER_DETAIL has further data such as USER_ID and IBAN.
The scenario is that multiple users can have the same IBAN. What I'm trying to do is create a query that shows where the same IBAN is being used by more than one user, with the number of users and the list of account numbers for each IBAN.
Db tables:
USER USER_DETAIL
________ ________
USER_ID ACCOUNT_NUM USER_ID IBAN
1, ACC001 1, IBAN001
2, ACC002 2
3, ACC003 3, IBAN002
4, ACC004 4, IBAN001
The query result I'm trying to achieve (showing that IBAN001 is being used by ACC001 and ACC004):
COUNT IBAN ACCOUNT_NUM
2 IBAN001 ACC001
ACC004
The part that's confusing me is the JOIN and GROUP BY. This works to get the count and IBAN:
SELECT COUNT(ud.user_id) AS num_users, ud.iban
FROM user_detail ud
WHERE ud.iban IS NOT NULL
GROUP BY iban
HAVING COUNT(ud.user_id) > 1
ORDER BY ud.iban
But when I try to join to the USER table and show all account numbers using each IBAN, I either get a "not a GROUP BY expression" error or the count is lost:
SELECT COUNT(ud.user_id) AS num_users, ud.iban, u.account_num
FROM user u
INNER JOIN user_detail ud USING (user_id)
WHERE ud.iban IS NOT NULL
GROUP BY ud.iban, u.account_num
HAVING COUNT(ud.user_id) > 1
ORDER BY ud.iban
If I understand correctly you want LISTAGG() to combine the accounts together in the aggregation results:
SELECT ud.iban, COUNT(*) as num_users,
LISTAGG(u.account_num, ',') WITHIN GROUP (ORDER BY u.account_num)
FROM user u INNER JOIN
user_detail ud
USING (user_id)
WHERE ud.iban IS NOT NULL
GROUP BY ud.iban
HAVING COUNT(*) > 1
ORDER BY ud.iban

how can I select rows that column does NOT have more than 1 value?

I am very new to SQL and I am wondering how to solve this issue. For example, my table looks as follows:
As you see in the table item_id 1 appears in both city_id 1 and 2, so does the item_id 4, but I want to get all the items where appears only in one city_id.
In this example, these would be item_id 2 (appearing only in city_id 2) and item_id 3 (appearing in city_id 1).
Use aggregation on item_id and count distinct values of city_id. The having clause can be used to filter on aggregates.
select item_id from mytable group by id having count(distinct city_id) = 1
You can use the following query:
SELECT item_id
FROM table_name
GROUP BY item_id
HAVING COUNT(DISTINCT city_id) = 1
In case you want to see the city_id to you can use this query:
SELECT item_id, MIN(city_id) AS city_id
FROM example
GROUP BY item_id
HAVING COUNT(DISTINCT city_id) = 1
Since there is only one city_id you can use MIN or MAX to get the id.
demo on dbfiddle.uk
You want all the id where they have only one distinct city:
SELECT item_id
FROM table
GROUP BY item_id
HAVING count(distinct city_id) = 1
It works by counting all the different values that city_id has for the same item_id. For those item ids where they repeat a lot, but the city_id is always the same the count of unique values in the city id is 1, and we can look for these using a HAVING clause. "Having" is like a where clause that runs after a GROUP BY operation is completed. It is the conceptual equivalent of this:
SELECT item_id
FROM
(
SELECT item_id, count(distinct city_id) as cdci
FROM table
GROUP BY item_id
) x
WHERE cdci = 1
If you want the city id too you can either get the MAX city (because in this case there is only one city so it's safe to do):
SELECT item_id, MAX(city_id) as city_id
FROM table
GROUP BY item_id
HAVING count(distinct city_id) = 1
or you could join this query back to the item table as a subquery:
SELECT t.*
(
SELECT item_id
FROM table
GROUP BY item_id
HAVING count(distinct city_id) = 1
) x
INNER JOIN
table t
ON x.item_id = t.item_id
This technique is the more general process for performing a group by that finds some particular set of rows, then bringing in the rest of the data from that row. You cant always stick every other column you want in a MAX because it will mix row data up, and you can't put the extra columns in your group by because that will subdivide what you're grouping on, giving the wrong results. Doing the group as a subquery and joining it back is a typical way to get all the row data when you have to group it to find which rows are interesting
In your case this form of query will bring all the duplicated rows (whereas the group by/max won't). If you don't want the duplicate rows you can make the top line SELECT DISTINCT t.* but don't make a habit of slapping distinct in to get rid of duplicated rows; if your tables don't have duplicates to start with but suddenly after you wrote a JOIN you got duplicated rows, google fornwhat a Cartesian product is in database queries and how to prevent it
You just need a group by on item id with having
Select item_id from table group by
item_id having count(distinct city_id)
=1
Also, if you want to have majority of same no of rows as input then
Select item_id, city, rank()
over(partition by item_id order by city)
rn
From table where rn=1;

Select rows where all in a group are not null postgresql

I have two tables: groups(group_id), member(group_id, name) and I would like to select all the members in groups where everyone in the group has a non-null name. For example, if this is the members table:
group_id|name
1|a
1|b
2|c
2|null
3|null
3|null
then the result of the query should return:
group_id|name
1|a
1|b
I tried running
SELECT * FROM members M1
WHERE ALL(SELECT M2.name IS NOT NULL FROM members M2)
ORDER BY M1.group_id
but it didn't work.
Use bool_and():
select group_id, name
from members
where group_id in (
select group_id
from members
group by 1
having bool_and(name is not null)
);
SELECT
*
FROM groups g
INNER JOIN members m
ON g.group_id = m.group_id
WHERE NOT EXISTS (SELECT * FROM members mbr WHERE mbr.name IS NULL AND mbr.group_id = m.group_id)
Essentially, we select all records, except for those where we can find a null name record with the same group ID.
Note that I don't believe this is SARG-able, so if you have a massive database that relies on indexes, this may be a bit on the slow side.
If you just need to group and display non null value, how if just a simple
SELECT group_id, name FROM members
group by group_id, name
having name is not null and id = 1;
Another solution:
SELECT * FROM Table
WHERE group_id NOT IN (
SELECT group_id FROM table
WHERE name IS NULL
)

How can I count the non-unique combinations of values in MySQL?

I have a table with some legacy data that I suspect may be a little messed up. It is a many-to-many join table.
LIST_MEMBERSHIPS
----------------
list_id
address_id
I'd like to run a query that will count the occurrences of each list_id-address_id pair and show the occurrence count for each from highest to lowest number of occurrences.
I know it's got to involve COUNT() and GROUP BY, right?
select list_id, address_id, count(*) as count
from LIST_MEMBERSHIPS
group by 1, 2
order by 3 desc
You may find it useful to add
having count > 1
select count(*), list_id, address_id
from list_membership
group by list_id, address_id
order by count(*) desc