Meta Stack Exchange is where users like you discuss bugs, features, and support issues that affect the software powering all 158 Stack Exchange communities.

What is meta?
Here's how it works:
  1. Any Stack Exchange user can ask a question
  2. The community provides support, votes on ideas, and reports bugs
  3. Your voice helps shape the way Stack Exchange operates

Can anybody muster up a query on Data Explorer that will show me my progress towards the Generalist badge?

share|improve this question
I think this is verging on spam. – nb69307 May 23 '10 at 10:10
@Neil, what now how? Can you explain to me what is spammy and how to fix it? More unicorns perhaps? – waffles May 23 '10 at 10:46
+1: Enquiring minds would like to know... – Charles Stewart May 23 '10 at 11:44
After reading the blog I came to ask the exact same question, so I'm happy someone beat me to it. – Ether May 24 '10 at 0:10
@Neil - You only say that because you got one. ;-D – Adam Davis May 25 '10 at 14:12
up vote 36 down vote accepted

Another try:

declare @temp table (id int identity(1,1), TagName char(128), score int);

with tags40 as (
  select top 40 tagid from posttags group by tagid order by count(*) desc

answers as (
  select score, id, parentId from posts  -- find responses of questions
  where communityowneddate is null   -- which are non-comm-wiki
  and posttypeid = 2                 -- answers
  and owneruserid = ##UserId##       -- by you

insert @temp(TagName, score)
select t.TagName, sum(a.score) as score from answers a
inner join posttags pt on pt.postid = a.parentId -- find tags of your answers
inner join tags40 f on f.tagid = pt.tagid        -- which are one of the top 40s
inner join tags t on f.tagid =
group by t.tagname
order by score desc

select *, case when score >= 15 then '' else '!' end from @temp
share|improve this answer
This looks correct for me. +1 – YOU May 23 '10 at 13:55
+1, seems to return the same as my approach. – Peter Lang May 23 '10 at 13:59
I'm accepting this, the id and ! mark are a nice touch, and it seems to run plenty fast – waffles May 24 '10 at 2:29

Unfortunately there is no way to tell when you are going to get the badge :)

However, this should show your progress with the top 40 tags:

With topTags As (
  Select Top 40 t.tagId
  From postTags t
  Group By t.tagId
  Order By Count(*) Desc
  Sum( a.score ) As Score,
  Sum( Case When Sum( a.score ) >= 15 Then 1 Else 0 End ) Over ( ) As ReachedTags
From topTags tt
Join postTags pt On ( pt.tagId = tt.tagId )
Join tags t On ( = tt.tagId )
Join posts q On ( = pt.postId
                  And q.postTypeId = 1             -- only questions have tags
                  And q.communityOwnedDate Is Null -- community
Join posts a On ( a.parentId = and a.communityOwnedDate is null)
Where a.ownerUserId = ##UserId##
Group By t.tagName
Order By score Desc
share|improve this answer
This can't be right: Also, are you filtering wiki posts? – Kobi May 23 '10 at 11:17
@Kobi: Thanks, I was missing the multiplication (10 for answers, 5 for questions) and the wiki post filtering. Fixed that now. – Peter Lang May 23 '10 at 11:28
Still weird - I have tons of regex and jquery questions, but none in the query: . Questions are not counted for this badge. This is a though one... – Kobi May 23 '10 at 11:31
No, you should not multiplicate the score. The p.Score is already exactly what the badge is checking on. – BalusC May 23 '10 at 11:32
@BalusC: Thanks for clarifying, reverted that change. – Peter Lang May 23 '10 at 11:38
Thanks for your patience, that's my first time working with this model. I was only counting question score instead of answer score, please retry :) – Peter Lang May 23 '10 at 11:47
something is still off with this query... debugging – waffles May 23 '10 at 12:54
@waffles: Much better, but something is still off .. In my case, I count 18 tags with >=15 score while I already have the Generalist badge. Edit: ach of course, your dump is almost 1 month old yet. – BalusC May 23 '10 at 13:24
@BalusC: I was checking for the ownerUserId of the question instead of the answer. waffles current approach sums the score of the questions instead of the answers, once this is fixed our queries return the same now. Still, this is not the same as the score I see in my profile... – Peter Lang May 23 '10 at 13:28
@Peter: the current dump is almost 1 month old. I needed only 3/5 more votes for 2 tags to get it and I can confirm this in my history. – BalusC May 23 '10 at 13:30
@waffles I still think it is off. It shows me as -3 for CSS where as I am sure I have at least 12. – HAL 9000 May 23 '10 at 13:36
This is a bit better there was a typo there keep in mind as others said, the data dump is almost a month old – waffles May 23 '10 at 13:38
@Yacoby: Both waffles' and my query seem to return 12 for CSS for your user... – Peter Lang May 23 '10 at 13:42
This appears wrong; Jon Skeet looks very far away from the generalist badge and I doubt he got all his missing votes in the last 23 days. – Andreas Bonini May 23 '10 at 16:02
@Kop: What are you talking about? Jon Skeet has more than enough votes there to get the badge. Remember, it's 20 tags, 15 upvotes on each. – Aarobot May 23 '10 at 17:00

Works now, all's cool

Peter Lang's script doesn't work for me: I'm posting the comment here, CWified, so that I can format the error message:

Error: System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'System.String'. at
 System.Data.Linq.IdentityManager.StandardIdentityManager.SingleKeyManager`2.TryCreateKeyFromValues(Object[] values, V& v)
 at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues) at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance)
 at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
 at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
 at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
 at CloudOverflowWeb.Helpers.QueryRunner.ExecuteNonCached(ParsedQuery parsedQuery, Site site, User user)
 in C:\Users\sam\Desktop\Source\cloudoverflow\CloudOverflow\CloudOverflowWeb\Helpers\QueryRunner.cs:line 141
 at CloudOverflowWeb.Helpers.QueryRunner.GetJson(ParsedQuery parsedQuery, Site site, User user)
 in C:\Users\sam\Desktop\Source\cloudoverflow\CloudOverflow\CloudOverflowWeb\Helpers\QueryRunner.cs:line 171
 at CloudOverflowWeb.Controllers.QueryController.Execute(String sql, Int32 siteId)
 in C:\Users\sam\Desktop\Source\cloudoverflow\CloudOverflow\CloudOverflowWeb\Controllers\QueryController.cs:line 110

Should I fix it? I'm so far from being a generalist, I don't even recognise what language it is written in... No, wait! I've got it: those insert/join/seclects mean it's some sort of query language, right? And the errors have some funny four-letter word "Linq" in them: I've seen that at Lambda the Ultimate: could that be the name of the language? Ha! [linq] isn't a top-40 tag, I'm fine. Phew, another technology I don't have to learn to become a generalist...

share|improve this answer
No repro. Both Peter's and my script work find with your user id. – kennytm May 24 '10 at 12:32
Don't get me started, LinqToSQL goes ape-crabs when you give it and non int primary keys, just discovered this now, will fix tomorrow. – waffles May 24 '10 at 12:52

Because of the tag “info” page, we have a faster up-to-date value of total tag score.

To run, go to any page in Stack Overflow, then paste the following into Firebug:

$.get('/tags', function(html) {
 var votes = [];

 console.log('Gathering data, please wait for 40 seconds...');

 $("", html).slice(0, 40).each(function(index, a) {
  var tagname = $(a).text();
  var href = '/tags/' + encodeURIComponent(tagname) + '/info';
   $.get(href, function(infoHtml) {
    var upvotes = $("#score-for-tag span", infoHtml).text();
    console.log(tagname, '->', upvotes);
    votes.push([+upvotes, tagname]);
    if (votes.length == 40) {
     votes.sort(function(x,y){return y[0]-x[0]});
     var res = ['<html><head><title>Generalist report</title></head><body><table><tr><th>Index</th><th>Tag</th><th colspan="2">Upvotes</th></tr>'];
     for (var l = 0; l < 40; ++ l) {
      if (votes[l][0] < 15)
  }, 1000*(index+1));


After you run it, the page will be replaced by a table summarizing the total upvotes of the top 40 tags. I think it's easy to convert into GreaseMonkey script but I'm lazy :)

Edit: Updated because the tag-wiki format is changed. Now it is accurate because the info page now shows the score instead of upvotes.

share|improve this answer

The KennyTM javascript version doesn't work for me (there is no score for tags where I have enough rights to edit the wiki), so here is my own version. Lazily I implemented it so you must run it from the Tags Page:

You also must change the user in the first line.

On the plus side: my version works, it shows some status updates (even without the firebug console) and it also displays gold, silver or bronze backgrounds according to the badge you already have for an individual tag:

// begin configure
var user = 'seanizer'; // your user name here
var mx = 5; // maximum ajax requests at any given time
// end configure

if ($('#result').size() == 0) {
            '<div id="result" class="answer" '
            + 'style="text-align:left;width:30ex;position:absolute;top:0;left:0;bottom:0;'
            + 'margin:0;padding:1em;background:#ccc"></div>'
$('#result').html('<p>Loading Tags...</p><ul></ul>');
var dt = [], tg = []; // data, tags
var bs = 0; // number of current requests
$('.post-tag:lt(40)').each(function(index, el) {
var dp; // dispatcher function
var ds = function() {
    var s = '<table style="background:white;">';
    dt.sort(function(a, b) {
        return (b[0] - a[0]);
        function(index, item) {
            var k = item[1], v = item[0];
            s = s + '<tr><td>'
            + k + '</td><td style="'
            + (v >= 1000 ? 'background:gold'
            : (v >= 400 ? 'background:silver'
            : (v >= 100 ? 'background:#A67D3D'
            : '')))
            + '">' + v + '</td><td>'
            + (v > 14 
            ? '<span style="color:green;font-weight:bold">&#x2713;</span>'
            : "") + "</td></tr>\n" + (index == 19 
            ? '<tr><td colspan="3"><b>You need 15 points in each row above'
                + ' this one to get the Generalist Badge</b></td></tr>'
            : '');
    s = s + "</table>";
    $('#result').html(s).find('td').css( {
        'padding' : '.3em',
        'text-align' : 'left'
dp = function() { // dispatcher function
    if (bs < mx && tg.length > 0) {
    if (tg.length === 0 && bs === 0) {
    } else {
        window.setTimeout(dp, 200);
var fs = function(tag) { // find tag score
        '' + tag + '/stats',
        function(response) {
            var score = $(response)
                .find("#questions .fl:eq(1) a:contains(" + user + ")")
            dt.push( [ !!score ? parseInt(score.replace(',','')) : 0, tag ]);
                $('<li>Loaded: <b>' + tag + "</b></li>")
dp(); // start dispatcher


And here is a minimized bookmarklet version:

javascript:var user='seanizer';eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('2 I=5;u($(\'#9\').17()==0){$(18.1a).J($(\'<z 1b="9" 16="13" \'+\'g="f-B:t;Z:10;11:12;1c:0;t:0;1d:0;\'+\'1k:0;F:1l;c:#1m"></z>\'))}$(\'#9\').A(\'<p>1n 1j...</p><q></q>\');2 h=[],8=[];2 d=0;$(\'.Y-e:1e(1f)\').r(6(m,E){8.M($(E).f().L())});2 i;2 D=6(){2 s=\'<K g="c:1g;">\';h.1h(6(a,b){1o(b[0]-a[0])});$.r(h,6(m,o){2 k=o[1],v=o[0];s=s+\'<7><4>\'+k+\'</4><4 g="\'+(v>=U?\'c:S\':(v>=V?\'c:W\':(v>=R?\'c:#X\':\'\')))+\'">\'+v+\'</4><4>\'+(v>14?\'<l g="Q:T;O-P:N">✓</l>\':"")+"</4></7>\\n"+(m==19?\'<7><4 1i="3"><b>1Q 1R 15 1P 1O r 1L 1T\'+\' 1N 1S 1W x 1U 1p 1V</b></4></7>\':\'\')});s=s+"</K>";$(\'#9\').A(s).j(\'4\').1X({\'F\':\'.1M\',\'f-B\':\'t\'})};i=6(){u(d<I&&8.C>0){G(8.1J())}u(8.C===0&&d===0){D()}1w{1K.1x(i,1y)}};2 G=6(e){d++;$.x(\'1v://1u.1q/1r/\'+e+\'/1s\',6(H){2 w=$(H).j("#1t .1z:1A(1) a:1G("+1H+")").1I("7").j("l").1F().1E().f().L();h.M([!!w?1B(w.1C(\',\',\'\')):0,e]);$(\'#9\').j("q").J($(\'<y>1D: <b>\'+e+"</b></y>"));d--})};i();',62,122,'||var||td||function|tr|tg|result|||background|bs|tag|text|style|dt|dp|find||span|index||item||ul|each||left|if||score|get|li|div|html|align|length|ds|el|padding|fs|response|mx|append|table|trim|push|bold|font|weight|color|100|gold|green|1000|400|silver|A67D3D|post|width|30ex|position|absolute|answer|||class|size|document||body|id|top|bottom|lt|40|white|sort|colspan|Tags|margin|1em|ccc|Loading|return|Generalist|com|tags|stats|questions|stackoverflow|http|else|setTimeout|200|fl|eq|parseInt|replace|Loaded|contents|first|contains|user|closest|pop|window|row|3em|this|in|points|You|need|one|above|the|Badge|to|css'.split('|'),0,{}));void(0)

Just create a new bookmark and paste this code into the URL (just change your user name). Remember: it only works from the tags page.

Edit: fixed a bug for huge scores containing a comma. Sorry, I ain't there yet :-)

share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .