Count registrations of different user types per day - sql

My table looks similar to this:
| date_of_register | account_type1 | account_type2 |
| 18/11/02 23:56:59 | type_a | type_b |
I want to count registrations of different types of users per day. account_type1 can be type_a or null, account_type2 can be type_b or null.
the result should look for one example day like this:
DATE | registers type_a | registers type_b|
18/11/02 | 32 | 21 |
But I want to make this for two months.
I'm not sure how to count records from different columns and get result like this. Is it possible?

You want to count occurrences per day. The day is the truncated date. So aggregate by TRUNC(<datecolumn>). Counting is easy, as you merely want to count non-null occurrences, which COUNT(<column>) is made for.
select
trunc(date_of_register),
count(account_type1) as registers_type_a,
count(account_type2) as registers_type_b
from mytable
group by trunc(date_of_register)
order by trunc(date_of_register);

You could do:
SELECT
TRUNC(date_of_register),
COUNT(CASE WHEN account_type1 = 'type_a' THEN 1 ELSE 0 END) AS "registers type_a",
COUNT(CASE WHEN account_type2 = 'type_b' THEN 1 ELSE 0 END) AS "registers type_b"
FROM registrations_table
GROUP BY TRUNC(date_of_register)

Related

How to create a table to count with a conditional

I have a database with a lot of columns with pass, fail, blank indicators
I want to create a function to count each type of value and create a table from the counts. The structure I am thinking is something like
| Value | x | y | z |
|-------|------------------|-------------------|---|---|---|---|---|---|---|
| pass | count if x=pass | count if y=pass | count if z=pass | | | | | | |
| fail | count if x=fail | count if y=fail |count if z=fail | | | | | | |
| blank | count if x=blank | count if y=blank | count if z=blank | | | | | | |
| total | count(x) | count(y) | count (z) | | | | | | |
where x,y,z are columns from another table.
I don't know which could be the best approach for this
thank you all in advance
I tried this structure but it shows syntax error
CREATE FUNCTION Countif (columnx nvarchar(20),value_compare nvarchar(10))
RETURNS Count_column_x AS
BEGIN
IF columnx=value_compare
count(columnx)
END
RETURN
END
Also, I don't know how to add each count to the actual table I am trying to create
Conditional counting (or any conditional aggregation) can often be done inline by placing a CASE expression inside the aggregate function that conditionally returns the value to be aggregated or a NULL to skip.
An example would be COUNT(CASE WHEN SelectMe = 1 THEN 1 END). Here the aggregated value is 1 (which could be any non-null value for COUNT(). (For other aggregate functions, a more meaningful value would be provided.) The implicit ELSE returns a NULL which is not counted.
For you problem, I believe the first thing to do is to UNPIVOT your data, placing the column name and values side-by-side. You can then group by value and use conditional aggregation as described above to calculate your results. After a few more details to add (1) a totals row using WITH ROLLUP, (2) a CASE statement to adjust the labels for the blank and total rows, and (3) some ORDER BY tricks to get the results right and we are done.
The results may be something like:
SELECT
CASE
WHEN GROUPING(U.Value) = 1 THEN 'Total'
WHEN U.Value = '' THEN 'Blank'
ELSE U.Value
END AS Value,
COUNT(CASE WHEN U.Col = 'x' THEN 1 END) AS x,
COUNT(CASE WHEN U.Col = 'y' THEN 1 END) AS y
FROM #Data D
UNPIVOT (
Value
FOR Col IN (x, y)
) AS U
GROUP BY U.Value WITH ROLLUP
ORDER BY
GROUPING(U.Value),
CASE U.Value WHEN 'Pass' THEN 1 WHEN 'Fail' THEN 2 WHEN '' THEN 3 ELSE 4 END,
U.VALUE
Sample data:
x
y
Pass
Pass
Pass
Fail
Pass
Fail
Sample results:
Value
x
y
Pass
3
1
Fail
1
1
Blank
0
2
Total
4
4
See this db<>fiddle for a working example.
I think you don't need a generic solution like a function with value as parameter.
Perhaps, you could create a view grouping your data and after call this view filtering by your value.
Your view body would be something like that
select value, count(*) as Total
from table_name
group by value
Feel free to explain your situation better so I could help you.
You can do this by grouping by the status column.
select status, count(*) as total
from some_table
group by status
Rather than making a whole new table, consider using a view. This is a query that looks like a table.
create view status_counts as
select status, count(*) as total
from some_table
group by status
You can then select total from status_counts where status = 'pass' or the like and it will run the query.
You can also create a "materialized view". This is like a view, but the results are written to a real table. SQL Server is special in that it will keep this table up to date for you.
create materialized view status_counts with distribution(hash(status))
select status, count(*) as total
from some_table
group by status
You'd do this for performance reasons on a large table which does not update very often.

Counting distinct stores SQL

I am fairly new to SQL and was wondering if anyone could help with my code.
I am trying to count the distinct number of stores that are tied to a certain Warehouse which is tied to a purchase order.
Example: If there are 100 stores with this PO that came from Warehouse #2 or #5 or etc... then I would like:
| COUNT_STORE | WH_LOCATION |
1 | 100 | 2 |
2 | 25 | 5 |
3 | 56 | 1 |
[]
My Code:
select count(distinct Store_ID) as Count_Store, WH_Location
from alc_Loc
where alloc_PO = 11345
group by Store_ID, WH_Location
When I run this I get a 1 for "count_store" and it shows me the WH_Location multiple times. I feel as if something is not tying in correctly.
Any help is appreciated!
Just remove store_id from the group by:
select count(distinct Store_ID) as Count_Store, WH_Location
from alc_Loc
where alloc_PO = 11345
group by WH_Location;
When you include Store_ID in the group by, you are getting a separate row for each Store_ID. The distinct count is then obviously 1 (or 0 if the store id is NULL).

sql Properly grouping my table

I'm using MS Access in order to play around with tables through SQL. I want to properly group my table and this is an example of what I want to do. Say I have a table like this:
Cool? | Age
Yes | 15
No | 34
No | 12
Yes | 26
Yes | 10
What I want is the resulting table to show how many ppl are cool or not grouped by age. For instance in this example it would be:
AGE | Count that are cool | Count that is Not cool
<25 | 2 | 1
>=25 | 1 | 1
Thanks in advance!
Try this:
case when age<25 then '<25' when age>=25 then '>=25' end as age, count(case when age<25 then 1 else null end) as [Count that are cool], count(case when age>=25 then 1 else null end) as [Count that is Not cool]
from Table1
group by case when age<25 then '<25' when age>=25 then '>=25' end

How to get max of multiple columns in oracle

Here is a sample table:
| customer_token | created_date | orders | views |
+--------------------------------------+------------------------------+--------+-------+
| 93a03e36-83a0-494b-bd68-495f54f406ca | 10-NOV-14 14.41.09.000000000 | 1 | 0 |
| 93a03e36-83a0-494b-bd68-495f54f406ca | 20-NOV-14 14.41.47.000000000 | 0 | 1 |
| 93a03e36-83a0-494b-bd68-495f54f406ca | 26-OCT-14 16.14.30.000000000 | 2 | 0 |
| 93a03e36-83a0-494b-bd68-495f54f406ca | 11-OCT-14 16.31.11.000000000 | 0 | 2 |
In this customer data table I store all of the dates when a given customer has placed an order, or viewed a product. Now, for a report, I want to write a query where for each customer (auth_token), I want to generate the last_order_date (row where orders > 0) and last_view_date (row where product_views > 0).
I am looking for an efficient query as I have millions of records.
select customer_token,
max(case when orders > 0 then created_date else NULL end),
max(case when views > 0 then created_date else NULL end)
from Customer
group by customer_token;
Update: This query is quite efficient because Oracle is likely to scan the table only once. Also there is an interesting thing with grouping - when you use GROUP BY a select list can only contain columns which are in the GROUP BY or aggregate functions. In this query MAX is calculated for the column created_date, but you don't need to put orders and views in a GROUP BY because they are in the expression inside MAX function. It's not very common.
When you want to get the largest value from a row, you need to use the MAX() aggregate function. It is also best practice to group a column when you are using aggregate functions.
In this case, you want to group by customer_token. That way, you'll receive one row per group, and the aggregate function will give you the value for that group.
However, you only want to see the dates where the cell value is greater than 0, so I recommend you put a case statement inside your MAX() function like this:
SELECT customer_token,
MAX(CASE WHEN orders > 0 THEN created_date ELSE NULL END) AS latestOrderDate,
MAX(CASE WHEN views > 0 THEN created_date ELSE NULL END) AS latestViewDate
FROM customer
GROUP BY customer_token;
This will give you the max date only when orders is positive, and only when views is positive. Without that case statement, the DBMS won't know which groups to give you, and you would likely get incorrect results.
Here is an oracle reference for aggregate functions.

SQLite: Finding top n aggregations for each distinct value in a column

Well that wasn't a very clear title, was it?
I have a SQLite table results:
event | dayOfWeek | hour| eventCount
--------+-----------+-----+------------
Event A | 0 | 0 | 4926
Event A | 0 | 1 | 1492
...
Event A | 1 | 0 | 7372
Event A | 1 | 1 | 49
...
Event B | 0 | 0 | 234648
...
It simply contains the number of time each event occurred at each hour of each day of the week.
I've been building a table daily like this:
create table daily as
select event,
sum(case when dayOfWeek = 0 then count else 0 end) as sunday,
sum(case when dayOfWeek = 1 then count else 0 end) as monday,
sum(case when dayOfWeek = 2 then count else 0 end) as tuesday,
sum(case when dayOfWeek = 3 then count else 0 end) as wednesday,
sum(case when dayOfWeek = 4 then count else 0 end) as thursday,
sum(case when dayOfWeek = 5 then count else 0 end) as friday,
sum(case when dayOfWeek = 6 then count else 0 end) as saturday
from results
group by event;
To get a table that looks like this:
event |sunday|monday|tuesday|wednesday|thursday|friday|saturday
--------+------+------+-------+---------+--------+------+---------
Event A | 345 | 2345 | 341 | 568 | 689 | 2351 | 1455
...
Which just contains counts for each event type for each day of the week. Building a similar table for hour of the day and for day/hour is trivial, and I have both tables available.
I'd like to make a table topTenPerHour like this:
hour | 1st | 2nd | 3rd | ...
-----+---------+---------+---------+------
0 | Event A | Event C | Event B | ...
1 | Event B | Event D | Event C | ...
...
23 | Event A | Event R | Event D | ...
But I'm having trouble seeing how. Any suggestions?
EDIT: I do not actually need to create a table (I only need to make a SELECT call), so SQLite's restrictions on CREATE TABLE (such as the unavailability of JOIN) do not apply to this problem.
You have set up your database in an overly complicated way here.
You should have:
an EventType table which defines each of your events
an EventLog table which registers each individual event, with "EventTypeId" foreign-key and timestamp.
Everything else you want to do will then be possible using database functions in queries. Trying to store all of this information in tables is redundant because it already inherently exists in your other tables. It should be the job of the program accessing your database to call the proper queries instead of the job of the database to save redundant information.
It is usually only a good idea to do this the way you have it set up now if you are making the same query over and over on static data (as in it very rarely updates). You would use it in that case only because you are worrying about optimizing the runtime of the query.
As you have seen in your other queries, SQL is not really designed to have multiple columns with similar meaning; you end up duplicating much code.
For the top n values, we need to compute their rank, which in this case is the number of records that do not hava a smaller event count for the same hour:
CREATE VIEW /* or TABLE */ ranks AS
SELECT hour,
event,
(SELECT COUNT(*)
FROM results
WHERE hour = hours.hour
AND eventCount >= hours.eventCount
) AS rank
FROM (SELECT DISTINCT event,
hour
FROM results) AS hours
We then take the value from the record with a specific rank for each column:
SELECT hour,
(SELECT event FROM ranks WHERE hour = h.hour AND rank = 1) AS "1st",
(SELECT event FROM ranks WHERE hour = h.hour AND rank = 2) AS "2nd",
...
FROM (SELECT DISTINCT hour
FROM results) AS h
ORDER BY hour