GROUP BY month when selecting a date Teradata SQL assistant - sql

SELECT EVENT_DT - ((EVENT_DT -DATE'1900-01-07') MOD 7) AS dates,
CLSFD_USER_ID AS user_id,
COUNT(DISTINCT CLSFD_USER_ID) AS number_of_user_ids,
COUNT(DISTINCT CLSFD_CAS_AD_ID) AS number_of_ads,
SUM(IMPRSN_CNT) AS number_of_impressions
FROM clsfd_access_views.CLSFD_CAS_AD_HST
WHERE CLSFD_SITE_ID = 3001
AND datum >= '2017-01-01'
GROUP BY 1,2
I want to have the total number of unique users during each month of the year 2017. I tried:
GROUP BY EXTRACT(MONTH FROM datum), 2
But this returns an error. What would be the most efficient code to retrieve the total number of user ids, ads, and impressions, per month.

It doesn't make sense to me to be aggregating by users, since they are what you are trying to count. Try grouping by the month and year alone:
SELECT
EXTRACT(YEAR FROM EVENT_DT) || '-' || EXTRACT(MONTH FROM EVENT_DT) AS month,
COUNT(DISTINCT CLSFD_USER_ID) AS number_of_user_ids,
COUNT(DISTINCT CLSFD_CAS_AD_ID) AS number_of_ads,
SUM(IMPRSN_CNT) AS number_of_impressions
FROM clsfd_access_views.CLSFD_CAS_AD_HST
WHERE
CLSFD_SITE_ID = 3001 AND
datum >= '2017-01-01' AND datum < '2018-01-01'
GROUP BY
EXTRACT(YEAR FROM EVENT_DT) || '-' || EXTRACT(MONTH FROM EVENT_DT);
Note that I changed your restriction on datum to also exclude any year greater than 2017.

If you want this values to be included in current query, then you should use analytical functions. For example "total number of unique users during each month" would be something like:
select count(distinct user_id) over(partition by EXTRACT(MONTH FROM datum))
Be aware that those values will be repeated for each user.

Related

Frequency distinct values grouped by date

I am trying to get the frequency of unique ID values for each month of the last year. However, I don't get the outcome.. including the error message "SELECT list expression references column user_id which is neither grouped nor aggregated".
How can I get the count of unique IDs in each month and them group them by month?
What I tried:
SELECT
user_id,
EXTRACT(MONTH FROM date) as month
FROM
TABLE
WHERE
date >= '2020-09-01'
GROUP BY
month
I want something like this:
month
count of unique user_id
1
300
2
200
...
...
12
250
You would use GROUP BY and COUNT(DISTINCT):
SELECT EXTRACT(MONTH FROM date) as month, COUNT(DISTINCT user_id)
FROM TABLE
WHERE date >= '2020-09-01'
GROUP BY 1;
I would advise you to include the year in the query. In BigQuery, this is simplest using DATE_TRUNC():
SELECT DATE_TRUNC(date, MONTH) as month, COUNT(DISTINCT user_id)
FROM TABLE
WHERE date >= '2020-09-01'
GROUP BY 1;

Count number of ids by Month SQL

I have a table like this, I hope to count the number of ids by month. I used the following code but it does not work.
id date_time
1390880502018723840,2021-05-08
1390881127930372100,2021-05-08
1390881498270736386,2021-05-08
SELECT twitter.tweets.id
WHERE Month(twitter.tweets.date_time)=01 AND Year(twitter.tweets.date_time)=2021 ;
you have to use count() function and to_char to get year month part of date in one column:
SELECT count(witter.tweets.id)
WHERE to_char(twitter.tweets.date_time,'YYYY-MM')= '2021-01';
you can generalize it for all the month/year by using group by :
SELECT to_char(twitter.tweets.date_time,'YYYY-MM') , count(witter.tweets.id)
group by to_char(twitter.tweets.date_time,'YYYY-MM');
To get counts for all months since Jan 2021:
SELECT date_trunc('month', date_time), count(*)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
GROUP BY 1;
If id can be NULL (which should be disallowed for an id column), use the slightly more expensive count(id) instead.
Count of distinct IDs:
SELECT date_trunc('month', date_time), count(DISTINCT id)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
GROUP BY 1;
For only Jan 2021:
SELECT count(DISTINCT id)
FROM twitter.tweets
WHERE date_time >= '2021-01-01'
WHERE date_time < '2021-02-01';

Month over Month percent change in user registrations

I am trying to write a query to find month over month percent change in user registration. \
Users table has the logs for user registrations
user_id - pk, integer
created_at - account created date, varchar
activated_at - account activated date, varchar
state - active or pending, varchar
I found the number of users for each year and month. How do I find month over month percent change in user registration? I think I need a window function?
SELECT
EXTRACT(month from created_at::timestamp) as created_month
,EXTRACT(year from created_at::timestamp) as created_year
,count(distinct user_id) as number_of_registration
FROM users
GROUP BY 1,2
ORDER BY 1,2
This is the output of above query:
Then I wrote this to find the difference in user registration in the previous year.
SELECT
*
,number_of_registration - lag(number_of_registration) over (partition by created_month) as difference_in_previous_year
FROM (
SELECT
EXTRACT(month from created_at::timestamp) as created_month
,EXTRACT(year from created_at::timestamp) as created_year
,count( user_id) as number_of_registration
FROM users as u
GROUP BY 1,2
ORDER BY 1,2) as temp
The output is this:
You want an order by clause that contains created_year.
number_of_registration
- lag(number_of_registration) over (partition by created_month order by created_year) as difference_in_previous_year
Note that you don't actually need a subquery for this. You can do:
select
extract(year from created_at) as created_year,
extract(month from created_at) as created_year
count(*) as number_of_registration,
count(*) - lag(count(*)) over(partition by extract(month from created_at) order by extract(year from created_at))
from users as u
group by created_year, created_month
order by created_year, created_month
I used count(*) instead of count(user_id), because I assume that user_id is not nullable (in which case count(*) is equivalent, and more efficient). Casting to a timestamp is also probably superfluous.
These queries work as long as you have data for every month. If you have gaps, then the problem should be addressed differently - but this is not the question you asked here.
I can get the registrations from each year as two tables and join them. But it is not that effective
SELECT
t1.created_year as year_2013
,t2.created_year as year_2014
,t1.created_month as month_of_year
,t1.number_of_registration_2013
,t2.number_of_registration_2014
,(t2.number_of_registration_2014 - t1.number_of_registration_2013) / t1.number_of_registration_2013 * 100 as percent_change_in_previous_year_month
FROM
(select
extract(year from created_at) as created_year
,extract(month from created_at) as created_month
,count(*) as number_of_registration_2013
from users
where extract(year from created_at) = '2013'
group by 1,2) t1
inner join
(select
extract(year from created_at) as created_year
,extract(month from created_at) as created_month
,count(*) as number_of_registration_2014
from users
where extract(year from created_at) = '2014'
group by 1,2) t2
on t1.created_month = t2.created_month
First off, Why are you using strings to hold date/time values? Your 1st step should to define created_at, activated_at as a proper timestamps. In the resulting query I assume this correction. If this is faulty (you do not correct it) then cast the string to timestamp in the CTE generating the date range. But keep in mind that if you leave it as text you will at some point get a conversion exception.
To calculate month-over-month use the formula "100*(Nt - Nl)/Nl" where Nt is the number of users this month and Nl is the number of users last month. There are 2 potential issues:
There are gaps in the data.
Nl is 0 (would incur divide by 0 exception)
The following handles this by first generating the months between the earliest date to the latest date then outer joining monthly counts to the generated dates. When Nl = 0 the query returns NULL indication the percent change could not be calculated.
with full_range(the_month) as
(select generate_series(low_month, high_month, interval '1 month')
from (select min(date_trunc('month',created_at)) low_month
, max(date_trunc('month',created_at)) high_month
from users
) m
)
select to_char(the_month,'yyyy-mm')
, users_this_month
, case when users_last_month = 0
then null::float
else round((100.00*(users_this_month-users_last_month)/users_last_month),2)
end percent_change
from (
select the_month, users_this_month , lag(users_this_month) over(order by the_month) users_last_month
from ( select f.the_month, count(u.created_at) users_this_month
from full_range f
left join users u on date_trunc('month',u.created_at) = f.the_month
group by f.the_month
) mc
) pc
order by the_month;
NOTE: There are several places there the above can be shortened. But the longer form is intentional to show how the final vales are derived.

Count records for first day of every month in a year

I have a table with 4 columns huge number of records. It has the following structure:
DATE_ENTERED EMP_NAME DATA ORIGINATED
01-JAN-20 A 545454 APPLE
I want to calculate no of records for every first day of every month in a year
is there any way can we fetch the data for every first day of month.
In oracle you can use TRUNC function on the date as follows:
SELECT TRUNC(DATE_ENTERED), COUNT(1) AS CNT
FROM YOUR_TABLE
WHERE TRUNC(DATE_ENTERED) = TRUNC(DATE_ENTERED, 'MON')
GROUP BY TRUNC(DATE_ENTERED, 'MON')
Please note that the TRUNC(DATE_ENTERED, 'MON') returns the first day of the month for DATE_ENTERED.
Cheers!!
SELECT Year, Month, COUNT(*)
FROM
(
SELECT
YEAR(DATE_ENTERED) Year
MONTH(DATE_ENTERED) Month
DAY(DATE_ENTERED) Day
FROM your_table
WHERE DAY(DATE_ENTERED) = 1
) A
GROUP BY Year, Month
Generally WHERE DAY(DATE_ENTERED) = 1 will get you the records only for dates at the start of each month. Thus using Year and Month function you can group them by in order to get a count for each year and each month
You mean something like
SELECT COUNT(*)
FROM Table
WHERE DAY(DATE_ENTERED) = 1 AND
YEAR(DATE_ENTERED) = Some_Year
GROUP BY DATE_ENTERED
You can also use DATE_ENTERED BETWEEN 'YYYY0101' and 'YYYY1231' (replace the YYYY with the year you want to retrieve data for) instead of YEAR(DATE_ENTERED) = Some_Year, if performance is an issue.
You can use something like this:
select * from your_table
where DAY(DATE_ENTERED) = 1
and DATE_ENTERED between '2020-01-01' and '2020-12-31'
for number of count use this:
select count(*) from your_table
where DAY(DATE_ENTERED)= 1
and DATE_ENTERED between '2020-01-01' and '2020-12-31'
UPDATE
select * from your_table where Extract(day FROM DATE_ENTERED) = 1 and DATE_ENTERED between '01-JAN-20 ' and '01-DEC-20 ';
this is how the data looks like:
For the list of records
select count(*) from your_table where Extract(day FROM DATE_ENTERED) = 1 and DATE_ENTERED between '01-JAN-20 ' and '01-DEC-20 ';
UPDATE-2
select EXTRACT(month from DATE_ENTERED) as Count,
to_char(to_date(DATE_ENTERED, 'DD-MM-YYYY'), 'Month') from your_table
where Extract(day FROM DATE_ENTERED) = 1 and DATE_ENTERED between '01-JAN-20
'and '01-DEC-20 ' group by EXTRACT(month from DATE_ENTERED),
to_char(to_date(DATE_ENTERED, 'DD-MM-YYYY'), 'Month');
Here is the output:

SQL Query to show all results before current month

I have a table in Oracle with columns: [DATEID date, COUNT_OF_PHOTOS int]
This table basically represents how many photos were uploaded per day.
I have a query that summarizes the number of photos uploaded per month:
select extract(year from dateid) as year, extract(month from dateid) as month, count(1) as Photos
from picture_table
group by extract(year from dateid), extract(month from dateid)
order by 1, 2
This does what I want, but I would like to run this query at the beginning of each month, lets say 07-02-2012, and have all data EXCLUDING the current month. How would I add a WHERE clause that ignores all entries that have a date equal to the current year+month?
Here is one way:
where to_char(dateid, 'YYYY-MM') <> to_char(sysdate, 'YYYY-MM')
To preserve any indexing strategy you may have on dateid:
select extract(year from dateid) as year, extract(month from dateid) as month, count(1) as Photos
from picture_table
WHERE (dateid < TRUNC(SYSDATE,'MM') OR dateid >= ADD_MONTHS(TRUNC(SYSDATE,'MM'),1))
group by extract(year from dateid), extract(month from dateid)
order by 1, 2