0

I have following two tables in the bottom of the post. The siteUsers table have a type column that can be "Member" or "Owner". I am looking for a SQL that shows how many members and owners each site has. I could do something like:

select 
    sites.Url,
    (select count(*) from siteusers where type='member' and siteusers.siteid=sites.siteid) as members,
    (select count(*) from siteusers where type='owners' and siteusers.siteid=sites.siteid) as owners
    from sites
    group by sites.url

However this is extreemly slow. Is there a faster and smarter way?

Sites table:

SiteId  int Unchecked
SPOSiteId   uniqueidentifier    Checked
Url nvarchar(MAX)   Checked

SiteUsers Table:

SiteUserId  int Unchecked
Type    nvarchar(256)   Checked
Name    nvarchar(512)   Checked
Email   nvarchar(512)   Checked
Host    nvarchar(256)   Checked
SiteId  int Checked

4 Answers 4

2

One way is:

select s.Url,
       sum(case when su.type = 'member' then 1 else 0 end) as members,
       sum(case when su.type = 'owners' then 1 else 0 end) as owners,
from sites s left join
     siteusers su
     on s.siteid = su.siteid
where su.type in ('member', 'owners')
group by s.url;
Sign up to request clarification or add additional context in comments.

Comments

1

You can do conditional aggregation with JOIN :

SELECT s.Url,
       SUM(CASE WHEN su.type ='member' THEN 1 ELSE 0 END) as members,
       SUM(CASE WHEN su.type ='owners' THEN 1 ELSE 0 END) as owners
FROM sites s INNER JOIN
     siteuser su
     ON su.siteid = s.siteid
GROUP BY s.Url;

However, you want index on sites(Url), siteuser(type) for better performance.

If the url is unique in sites, then this should be fast with the right indexes:

select s.Url,
    (select count(*) from siteusers su where su.type = 'member' and su.siteid = s.siteid) as members,
    (select count(*) from siteusers su where su.type = 'owners' and su.siteid = s.siteid) as owners
from sites s;

The right index is on siteusers(siteid, type). Of course, this assumes that url is unique which may not be the case.

1 Comment

You totally right I dont know why I have group by when all is unique!
1

Use Group By

 select s.Url,su.type, count(*)

 from sites s join
 siteusers su
 on s.siteid = su.siteid

 group by s.url,su.type

1 Comment

OOhh guyyss som many good answers! Damn I can only mark one answers :( But thanks all highly appreciated!
1

I'd first check that proper primary keys and indexes are built:

  • table Sites should have primary key SiteId
  • table SiteUsers should have primary key SiteUserId
  • table SiteUsers should have index on SiteId, type

then you can run following query to get results:

select s.url, t.members, t.owners
from Sites s inner join
(
  select
    SiteId, 
    sum(case when Type = 'member' then 1 else 0 end) as members,
    sum(case when Type = 'owners' then 1 else 0 end) as owners
  from SiteUsers
  group by SiteId
) t on s.SiteId = t.SiteId

this way you avoid group by varchar column

sample fiddle http://sqlfiddle.com/#!18/0b9b7/4

1 Comment

That runs very fast! The index and PK was allready in place. Sweet!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.