Dynamic Total Count for Percentage Value - Dataview Query

Hi,

I stumbled over a post post for my problem. I just can’t get it to work completely.

The first code gives me the total number

TABLE length(rows) as Count, Ratio
FROM "Folder" 
FLATTEN reviewtags as Reviewtags
GROUP BY true

The second code gives me almost the desired result

```dataview
TABLE length(rows) as Count, Ratio
FROM "Folder" 
GROUP BY containsword(reviewtags, "early") 
SORT length(rows.file.name) desc

How can I combine this in on table to build a ratio/percentage?

  • where e.g. 3/167, 134/167, or 30/167

I’m trying since hours and I simply not skilled enough yet to get this to work. I really would appreciate a helping hand.

Thank you

Michael

It’s not trivial to both get the overall total, and also the total of a given case within the same table. I tend sometimes to use dataviewjs to do this, but there are at least two other options, which I’ll explore below:

Using filter and GROUP BY true

You’ve presented queries which are able to calculate each of the totals, and you could’ve expanded the one getting the overall total, to do a filter counting only the valid test cases within the resulting rows.

However when you’re using containsword() to check you need to be aware that this function works different when presented with a list versus a string. See its documentation.

One query to do this using that function would be to do:

```dataview
TABLE WITHOUT ID
  totalCount, posCount, negCount, rows.testCase
FROM "ForumStuff/f69/f69984"
WHERE subject
FLATTEN any(containsword(subject, "first")) as testCase
GROUP BY true

FLATTEN length(rows) as totalCount
FLATTEN length(filter(rows.testCase, (r) => r)) as posCount
FLATTEN length(filter(rows.testCase, (r) => !r)) as negCount
```

Note that my queries use the FROM "ForumStuff/..." and tests the subject for first, instead of your examples, so you need to change those to match your case.

Another option with the same kind of result would be to use contains():

TABLE WITHOUT ID
  totalCount, posCount, negCount
FROM "ForumStuff/f69/f69984"
WHERE subject
GROUP BY true
FLATTEN length(rows) as totalCount
FLATTEN length(filter(rows.subject, (r) => contains(r, "first") )) as posCount
FLATTEN length(filter(rows.subject, (r) => !contains(r, "first") )) as negCount

This latter one would possibly be easier to use if you wanted to test for multiple cases, but it kind of depends on preferences.

Using dual GROUP BY statements

Yet another variant would be to use dual GROUP BY statements. By this I mean that we first do a query listing all rows to be included in the statistics, preferably with extra variables (by using FLATTEN) denoting the various test cases.

Ignoring the first line, which is heavily impacted by later statements, we could imagine this to look like:

TABLE count, round(count / total, 2) as Ratio
FROM "ForumStuff/f69/f69984"
WHERE subject
FLATTEN any(containsword(subject, "first")) as testCase

Same caveats as before regarding the folder, subject and text to match for.

On this overall query we do the first group by to gives us the total number of rows in our test set, and then we proceed to split this set into groups for each test case.

GROUP BY true

FLATTEN length(rows) as totalCount
FLATTEN rows.testCase as case

Finally we group by each test case, and do some final calculation and beautifications on our variables, to allow for the first line (with TABLE) to be manageable and readable:

GROUP BY case

FLATTEN length(rows) as count
FLATTEN rows.totalCount[0] as total

Gather all of these pieces back into one query, and you should be good to go with one row for each of the test cases. An untested version corrected back to your environment should look something like:

```dataview
TABLE count, round(count / total, 2) as Ratio
FROM "Folder"
WHERE reviewtags
FLATTEN any(containsword(reviewtags, "early")) as testCase

GROUP BY true

FLATTEN length(rows) as totalCount
FLATTEN rows.testCase as case
GROUP BY case

FLATTEN length(rows) as count
FLATTEN rows.totalCount[0] as total
```
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.