Sum the result of count() - sql

I have a table like this.
-----------------
|City |Block |
-----------------
|Bekasi |A1 |
|Bekasi |A1 |
|Jakarta |A1 |
|Jakarta |A2 |
|Bandung |A3 |
-----------------
What is the correct query if I want to count subtotal of Bekasi's block as 1, Jakarta's block as 2 and Bandung's block as 1, so it will return total values like this?
-----------------
|City |Block |
-----------------
|Bekasi |A1 |
|Bekasi |A1 |
|Jakarta |A1 |
|Jakarta |A2 |
|Bandung |A3 |
-----------------
|TOTAL |4 |
-----------------
I tried using this query
SELECT COUNT(DISTINCT block) AS total FROM report GROUP BY city
But it will only return a result like this.
--------
|Total |
--------
|1 |
|1 |
|2 |
--------
Please help me, thanks.

This will give you the sum of the total count
select SUM(a.total)
from
(SELECT COUNT(DISTINCT block) AS total FROM report GROUP BY city) a
And if you want the data and total in the same query you could do something like this:
select 1 as rank, city, count(city) from report group by city
union all
select 2 as rank, 'Total', SUM(a.total)
from
(SELECT COUNT(DISTINCT block) AS total FROM report GROUP BY city) a
order by rank asc

Try This
select City,count(distinct Block) from report group by City With RollUp

select count (t) from (
select city,count(block) as t from report group by city, block) s
group by city

Related

How to sum duplicates SQL/PSQL

I have some problem with how to build a query to sum all duplicates, in this query below I can count all occurrences.
SELECT COUNT (*) occurrences
FROM back.submission s
GROUP BY s.name
HAVING COUNT(*) > 1
----------
|# |occurrences|
|1 | 9 |
|2 | 6 |
|3 | 5 |
|4 | 4 |
|5 | 4 |
|6 | 3 |
....
I would like to know how to sum all occurrences, i tried to put count inside SUM, but it doesn't work
Do you want an other level of aggregation?
SELECT COUNT(occurences) AS count_of_duplicates, SUM(occurences) AS sum_of_duplicates
FROM (
SELECT COUNT (*) occurrences
FROM back.submission s
GROUP BY s.name
HAVING COUNT(*) > 1
) t
SELECT #,count(*) As Total FROM back.submission GROUP BY # HAVING COUNT(*) > 1;
With CTE
As
(
Select [#],Count([*]) As Total From back.submission Group By [#]
)
select [#],Total From CTE Where Total>1

How to get values of different columns by different roles on other columns in oracle

I have a table that include few row from each clientID. each row came from different company and different validation date.
for example (you can find it at this link too):
ID |COMPANY|GENDER|AGE|IS_SMOKER|VALIDATION_DATE |ZIP |ZIP_VALIDATION_DATE
--------------------------------------------------------------------------------
1111 | 1 | m |44 | 1 | 02-MAR-03 |12345 |02-MAR-03
1111 | 3 | m |43 | NULL | 03-FEB-10 |11111 |03-FEB-00
2222 | 1 | f |20 | 0 | 04-APR-00 |22344 |04-APR-00
2222 | 3 | f |50 | 0 | 05-MAY-82 |22344 |05-MAY-82
3333 | 1 | f |34 | 0 | 05-MAY-01 |33333 |01-MAY-00
3333 | 7 | f |34 | 1 | 05-MAY-00 |22222 |05-MAY-00
4444 | 3 | m |95 | NULL | 06-JUN-03 |12345 |02-MAR-03
I want to get one line per ID but with different role for each data:
zip code but the max of ZIP_VALIDATION_DATE
smoker - if it is smoker (1) in any company get 1 else if it have 0 get 0 if null get null
other data - by max VALIDATION_DATE
The result I want is:
ID |GENDER|AGE|IS_SMOKER|ZIP
---------------------------------
1111 | m |43 | 1 |12345
2222 | f |20 | 0 |22344
3333 | f |34 | 1 |22222
4444 | m |95 | NULL |12345
NOTE:
the validation_date is good for several columns when ZIP_VALIDATION_DATE is valide only for one columns.
I have few more columns with different role (like the smoker) and another specific validation date but. I didn't add it to the example but I suppose it will be the same implementation.
I try to find the most efficient way to do this, but I don't have limitation to use OVER PARTITION, WITH, sub_query or something else.
If I follow the logic correctly, you can use Oracle's keep functionality with aggregation:
select id,
max(gender) keep (dense_rank first order by validation_date desc) as gender,
max(is_smoker),
max(age) keep (dense_rank first order by validation_date desc) as age,
max(zip) keep (dense_rank first order by ZIP_VALIDATION_DATE desc) as zip
from my_table t
group by id
order by id;
Here is a db<>fiddle.
Please use below query,
select id, gender, age, is_smoker, zip from
(select id, gender, age, is_smoker, zip,
row_number() over(partition by id order by validation_date desc) as rnk
from table_name) qry where rnk = 1;
below is the demo,
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=c834e8e07d58f714955eccb9704fc34b

Get count of all instances before a certain date

I have a table like this:
--------------------------------------
RecID|name |date
--------------------------------------
1 |John | 05/09/2016
2 |John | 05/02/2016
3 |Mary | 05/09/2016
4 |Mary | 05/08/2016
5 |Mary | 03/02/2016
and I want to get the count for name for each instance in which that name has appeared on or before that date in the row. So I want the output to look like this:
--------------------------------------
RecID|name |date |count
--------------------------------------
1 |John | 05/09/2016 | 2
2 |John | 05/02/2016 | 1
3 |Mary | 05/09/2016 | 3
4 |Mary | 05/08/2016 | 2
5 |Mary | 03/02/2016 | 1
Any ideas on how I should go about doing this?
You can use the count function with a window specification.
select t.*, count(*) over(partition by name order by date) as cnt
from tablename t
This will produce incorrect results if there are mutliple rows on a given date for a name. One way to avoid this is using a correlated sub-query.
select t.*,
(select count(distinct t2.date)
from tablename t2
where t2.name=t.name and t2.date<=t.date) as cnt
from tablename t
Or use row_number.
select t.*, row_number() over(partition by name order by date) as cnt
from tablename t
Or use dense_rank if there can be multiple rows for the same name on a given date.
select t.*, dense_rank() over(partition by name order by date) as cnt
from tablename t
The easiest solution of all would be to use dense_rank.
use
count(*) count
and
group by date
if your date is already a string (i.e. without hour/minute information)

Percentage of requests SQL

So, I have this table:
Table1
|Number | abc |
|100 | No |
|200 | No |
|300 | Yes |
|400 | No |
|500 | No |
What I want is the percentage of values that is "yes". In this case, the desired OUTPUT is 20%
I thought that by dividing the number of "yes" by the total number It would do it, but i can't "join" all things.
I know that the number of "yes" is
select count(abc)
from table1
where abc='yes'
And the total number is
select count(*)
from table1
How do i get the desired output?
A query that works in all SQL engines is
select sum(case when abc = 'yes' then 1 else 0 end) * 100 / count(*)
from your_table

Add order column into query result in SQL Server

I have a table, called Table1 that looks like:
id|val1|val2|FKId
------------------
1|val |val | 123
2|val |val | 123
3|val |val | 234
4|val |val | 345
I'm using:
SELECT * FROM Table1
I need to add to the result of this query, a column that will contain the order number for each row by FKId. Result that I need looks like:
id|val1|val2|FKId |Order
------------------------
1|val |val | 123 | 1
2|val |val | 123 | 1
3|val |val | 234 | 2
4|val |val | 345 | 3
Maybe there is some function in SQL Server to get this?
Using Ranking function Dense_Rank() you can get the required order. To know more about Dense_rank check here.
SELECT *,
Dense_Rank()
OVER (
PARTITiON BY val1
ORDER BY fkid) [Order]
FROM tablename