SQL COUNT of COUNT - sql

I have some data I am querying. The table is composed of two columns - a unique ID, and a value. I would like to count the number of times each unique value appears (which can easily be done with a COUNT and GROUP BY), but I then want to be able to count that. So, I would like to see how many items appear twice, three times, etc.
So for the following data (ID, val)...
1, 2
2, 2
3, 1
4, 2
5, 1
6, 7
7, 1
The intermediate step would be (val, count)...
1, 3
2, 3
7, 1
And I would like to have (count_from_above, new_count)...
3, 2 -- since three appears twice in the previous table
1, 1 -- since one appears once in the previous table
Is there any query which can do that? If it helps, I'm working with Postgres. Thanks!

Try something like this:
select
times,
count(1)
from ( select
id,
count(distinct value) as times
from table
group by id ) a
group by times

Related

How to get WHERE come after group by in sqlite3

I am working with a dataset, I used GROUP BY to get the count of one of the columns. Then, I want to filter the columns with count > 2, I find that WHERE does not work after GROUP BY, may I ask what should I do?
For example, for the id_table with only one column id with the numbers [2, 3, 2, 3, 4, 2], I want to count each and find which id appears more than two times, in this case, the output should be 2 since it appeared 3 times. My code is like below:
SELECT id
FROM id_table
GROUP BY id
WHERE count(id) > 2;
The error code is: near "WHERE": syntax error
Try this (HAVING instead of WHERE):
SELECT id
FROM id_table
GROUP BY id
HAVING count(id) > 2
;

How can I read the first n rows of table a based upon the number of rows in table b?

I have a table "L20" that contains 1 to 20 values "HDIF" in it, sorted in ascending order. I need to extract the first 1 to 10 of those values into table "T10" depending upon the number of values in table "L20". I'm using Windows 10, Libreoffice 6.4.4, with Firebird 3 database. I've tried the CASE statement and the DECODE statement on the COUNT of rows in "L20", but neither seems to work.
If I put in a numeral for the SELECT on table "L20" then it works correctly. Anyone have an idea of how to solve? The purpose of this query is to calculate a golf handicap which uses [up to] the best (lowest) 10 scores of [up to] the last (most recent) 20 games played. Here is the coding:
/* Qry_Index_Calc - calculates handicap index from top 10 differentials of last 20 games */
/* Source is "VW_Plyr_Diff" which has handicap differentials already calculated. */
SELECT (AVG ("T10"."HDIF") * .96) "Index", (Count ("T10"."HDIF")) FROM
/* Get only the games needed if less than 20 games have been played. */
(
SELECT FIRST
DECODE ((SELECT COUNT (*) FROM "L20"),
1, 1
, 2, 1
, 3, 1
, 4, 1
, 5, 1
, 6, 1
, 7, 2
, 8, 2
, 9, 3
, 10, 3
, 11, 4
, 12, 4
, 13, 5
, 14, 5
, 15, 6
, 16, 6
, 17, 7
, 18, 8
, 19, 9
, 10)
"L20"."HDIF"
FROM
/* Get up to 20 of the most recent (last) games played. */
( SELECT FIRST 20 "PlayerID" "PID", "GID" "GID",
RANK ( ) OVER ( PARTITION BY "PlayerID" ORDER BY "Diff" ) "Rnk",
"Diff" "HDIF", "Date" "Gdate"
FROM "Vw_Plyr_Diff"
WHERE "PlayerID" = 1)
"L20"
) "T10"
You need to put parentheses around the expression in FIRST. As specified in the Firebird 3.0 Language Reference for FIRST, SKIP:
SELECT
[FIRST <m>] [SKIP <n>]
FROM ...
...
<m>, <n> ::=
<integer-literal>
| <query-parameter>
| (<integer-expression>)
So, use
select first (decode(...)) ....
When using subqueries directly in first, you need to use double parentheses (once for the expression, and once for the fact that sub-queries in expressions are enclosed in parentheses.
The SQL standard OFFSET/FETCH clauses introduced in Firebird 3 do not support expressions.
Beware, your current code doesn't specify an ORDER BY, this means it is undefined exactly which rows are returned, it will depend on location of data inside the database, the access plan, etc. I would recommend that you add an appropriate ORDER BY clause to ensure the returned rows are as expected.
It looks like you're trying to SELECT from the derived table L20 defined in the FROM clause, and not from an actual table L20. If you want to be able to do that, then L20 most be specified as a common table expression.

capture non occured data from dynamic input data

I have data rules like given below
1|Group1|Mandatory|1st occurrence
2|Group1|Optional|1st occurrence
3|Group1|Mandatory|1st occurrence
1|Group1|Mandatory|2nd occurrence
2|Group1|Optional|2nd occurrence
3|Group1|Mandatory|2nd occurrence
4|Group2|Mandatory|1st occurrence
5|Group2|Mandatory|1st occurrence
6|Group2|Optional|1st occurrence
Here as you can see Group 1 is present two times for data record 1, 2 and 3. It means group 1 can appear min 1 time and max two times. And also can see the occurrence of that specific record under group 1 when it occurs. Mandatory should occur always and optional is may or may not be occur in input data. But all needs to be captured ..what's missing
And here is my input column data. That's a only column am having in input data
1
2
3
1
2
4
5
Is there any way I could get result to identify which data set if missing according to data rules table from input data ? Like in this example, output should like saying Mandatory record(3) is missing from Group 1 in second occurrence. That's only available information would be coming from input data and data rules table.
If any things needs to be added to get desired result...I would like to hear..what it is. All suggestions are welcome.
Thanks
I think You need something like this:
with input as (select column_value id,
count(1) over (partition by column_value order by null
rows between unbounded preceding and current row) cnt
from table(sys.odcinumberlist(1, 2, 3, 1, 2, 4, 5)))
select *
from data
where status = 'Mandatory'
and (id, occurence) not in (select id, cnt from input)
demo
ID GRP STATUS OCCURENCE
---- ---------- ---------- ---------
3 Group1 Mandatory 2
Count how many times id appears in input data and compare result with mandatory occurences in your data.
Edit: explanation
select column_value id,
count(1) over (partition by column_value order by null
rows between unbounded preceding and current row) cnt
from table(sys.odcinumberlist(1, 2, 3, 1, 2, 4, 5))
This part simulates you input data. table(sys.odcinumberlist(1, 2, 3, 1, 2, 4, 5)) is just simulation of inputs, probably these ids are in some table, select them from there. For each provided id I'm counting it's growing number of occurences using function count() in analytic version, so we have this:
id cnt
--- ---
1 1
1 2
2 1
2 2
3 1
4 1
5 1
Next these pairs are compared with mandatory pairs (id, occurence) in your data. If something is missing last select displays this row with a clause not in.
This is how I understood Your question, perhaps You'll need some modifications, but now You have some hints. Hope this helps (and sorry for my bad English ;-) ).

Access ancestors

I have an Access db table, that holds couples of values: (SourceId, DestinationId). Both values are taken from the same list of Id's.
I want to create a list (query result?) of all item's ancestors. Ie, if the user enters Id=15, I'd like to return all Id's that are destinations for source-15, but also their destinations etc.
For example, if my table hold
15, 3 |
15, 4 |
4, 7 |
4, 8 |
3, 5 |
5, 2 |
1, 9
Id like to return 3, 4, 7, 8, 5, 2 (but not return 9).
I guess the solution should include some VBA code with loops or recursion, but I got confused by recordsets versus collections.
Any idea?
Thanks,
Aviram
Unfortunately Access SQL lacks the CONNECT BY syntax that Oracle uses to do hierarchical queries. However, if you are prepared to create a temporary table you can emulate it in Access with a loop.
In this example your original table is "LinkTab" and the temporary table will be "TmpTree" an you are starting from SourceID 15.
First execute:
SELECT SourceID, DestID, 1 as Lvl INTO TmpTree FROM LinkTab WHERE SourceID = 15
Then in a loop, repeatedly execute:
INSERT INTO TmpTree ( SourceID, DestID, Lvl )
SELECT newrows.SourceID, newrows.DestID, TmpTree.Lvl + 1
FROM TmpTree INNER JOIN LinkTab newrows ON TmpTree.DestID = newrows.SourceID
WHERE TmpTree.Lvl = (SELECT MAX(Lvl) FROM TmpTree)
until the statement returns zero affected rows (or if you can't detect this, count the rows in TmpTree each time and stop when they don't increase)
Now your results can be retrieved with :
SELECT DestID FROM TmpTree
And finally, to tidy up:
DROP TABLE TmpTree
I've tested these statements in the Access Query designer and they get the desired result.

Oracle: Select multiple values from a column while satisfying condition for some values

I have a column COL in a table which has integer values like: 1, 2, 3, 10, 11 ... and son on. Uniqueness in the table is created by an ID. Each ID can be associated with multiple COL values. For example
ID | COL
——————————
1 | 2
————+—————
1 | 3
————+—————
1 | 10
————+—————
is valid.
What I want to do is select only the COL values from the table that are greater than 3, AND (the problematic part) also select the value that is the MAX of 1, 2, and 3, if they exist at all. So in the table above, I would want to select values [3, 10] because 10 is greater than 3 and 3 = MAX(3, 2).
I know I can do this with two SQL statements, but it's sort of messy. Is there a way of doing it with one statement only?
SELECT col FROM table
WHERE
col > 3
UNION
SELECT MAX(col) FROM table
WHERE
col <= 3
This query does not assume you want the results per id, because you don't explicitely mention it.
I don't think you need pl/sql for this, SQL is enough.