SQLite - Use a CTE to divide a query - sql

quick question for those SQL experts out there. I feel a bit stupid because I have the feeling I am close to reaching the solution but have not been able to do so.
If I have these two tables, how can I use the former one to divide a column of the second one?
WITH month_usage AS
(SELECT strftime('%m', starttime) AS month, SUM(slots) AS total
FROM Bookings
GROUP BY month)
SELECT strftime('%m', b.starttime) AS month, f.name, SUM(slots) AS usage
FROM Bookings as b
LEFT JOIN Facilities as f
ON b.facid = f.facid
GROUP BY name, month
ORDER BY month
The first one computes the total for each month
The second one is the one I want to divide the usage column by the total of each month to get the percentage
When I JOIN both tables using month as an id it messes up the content, any suggestion?

I want to divide the usage column by the total of each month to get the percentage
Just use window functions:
SELECT
strftime('%m', b.starttime) AS month,
f.name,
SUM(slots) AS usage
1.0 * SUM(slots) AS usage
/ SUM(SUM(slots)) OVER(PARTITION BY strftime('%m', b.starttime)) ratio
FROM Bookings as b
LEFT JOIN Facilities as f
ON b.facid = f.facid
GROUP BY name, month
ORDER BY month

Related

Most rented movie by title PostgreSQL sample database

I am working on getting the most popular movies rented per month by title. So far I have been able to get the titles of the movies and the dates they were rented but the count column and date column are giving individual results. Here is the query I am using. Any help would be much appreciated.
SELECT x.rental_date, x.title, x.count FROM(
SELECT ren.rental_date,fil.title,COUNT(ren.rental_id)
FROM rental AS ren
JOIN inventory AS inv ON ren.inventory_id = inv.inventory_id
JOIN film AS fil ON inv.film_id = fil.film_id
GROUP BY title, rental_date) AS x
ORDER BY x.count,x.rental_date;
Simply aggregate by the year/month of the specific dates using to_char. Also, subquery is not necessary.
SELECT TO_CHAR(ren.rental_date, 'YYYY-MM') AS rental_month,
fil.title,
COUNT(ren.rental_id) AS rental_count
FROM rental AS ren
JOIN inventory AS inv
ON ren.inventory_id = inv.inventory_id
JOIN film AS fil
ON inv.film_id = fil.film_id
GROUP BY TO_CHAR(ren.rental_date, 'YYYY-MM'),
fil.title
ORDER BY rental_month,
rental_count DESC
Consider also date_part for year and month extraction or date_trunc to normalize dates to first day of month to keep the timestamp type:
SELECT DATE_PART('year', ren.rental_date) AS rental_year,
DATE_PART('month', ren.rental_date) AS rental_month,
...
SELECT DATE_TRUNC('month', ren.rental_date) AS rental_month,
...

Is there a way to count how many strings in a specific column are seen for the 1st time?

**Is there a way to count how many strings in a specific column are seen for
Since the value in the column 2 gets repeated sometimes due to the fact that some clients make several transactions in different times (the client can make a transaction in the 1st month then later in the next year).
Is there a way for me to count how many IDs are completely new per month through a group by (never seen before)?
Please let me know if you need more context.
Thanks!
A simple way is two levels of aggregation. The inner level gets the first date for each customer. The outer summarizes by year and month:
select year(min_date), month(min_date), count(*) as num_firsts
from (select customerid, min(date) as min_date
from t
group by customerid
) c
group by year(min_date), month(min_date)
order by year(min_date), month(min_date);
Note that date/time functions depends on the database you are using, so the syntax for getting the year/month from the date may differ in your database.
You can do the following which will assign a rank to each of the transactions which are unique for that particular customer_id (rank 1 therefore will mean that it is the first order for that customer_id)
The above is included in an inline view and the inline view is then queried to give you the month and the count of the customer id for that month ONLY if their rank = 1.
I have tested on Oracle and works as expected.
SELECT DISTINCT
EXTRACT(MONTH FROM date_of_transaction) AS month,
COUNT(customer_id)
FROM
(
SELECT
date_of_transaction,
customer_id,
RANK() OVER(PARTITION BY customer_id
ORDER BY
date_of_transaction ASC
) AS rank
FROM
table_1
)
WHERE
rank = 1
GROUP BY
EXTRACT(MONTH FROM date_of_transaction)
ORDER BY
EXTRACT(MONTH FROM date_of_transaction) ASC;
Firstly you should generate associate every ID with year and month which are completely new then count, while grouping by year and month:
SELECT count(*) as new_customers, extract(year from t1.date) as year,
extract(month from t1.date) as month FROM table t1
WHERE not exists (SELECT 1 FROM table t2 WHERE t1.id==t2.id AND t2.date<t1.date)
GROUP BY year, month;
Your results will contain, new customer count, year and month

How to get a timeline with zero observations for stores not selling

I have an issue with a table I would like to create.
I have a table for accumulated sales for each store for each day where the store had a sale. Meaning that if the store didn't have a sale on a specific day, there's no line for this observation.
what I would like is a line for each store for each day, also the days where the store didn't have any sales, in this case the daily sales would just be zero.
I've tried making a full outer join between a daily generate_series and the table mentioned above.
select
timeline::date as date,
store_rev.store_name,
store_rev.store_daily_rev
FROM generate_series(
'2017-03-01',
now(),
'1 day') AS timeline
FULL OUTER JOIN(select
r.date,
r.store_name,
r.store_daily_rev,
FROM revenue r) store_rev ON timeline.date=store_rev.date
But this doesn't give me a row of zero if the store didn't have any sales.
Hope you guys can help me out. Thanks!
Are you sure that column date in table revenue is type DATE
I modifited your query, try this:
select
timeline::date as date,
store_rev.store_name,
store_rev.store_daily_rev
from
(
select
timeline::date as date
from
generate_series('2017-03-01', now(),'1 day') AS timeline
) timeline
JOIN(select
r.date,
r.store_name,
r.store_daily_rev,
FROM revenue r) store_rev ON timeline.date::date = store_rev.date::date;
I think you want a cross join followed by a left join. This will get all combinations:
select timeline.date, s.store_name,
coalesce(r.store_daily_rev, 0) as store_daily_rev
from generate_series('2017-03-01', now(), '1 day') as timeline(date) cross join
(select distinct r.store_name from revenue r) s left join
revenue r
on r.store_name = s.store_name and r.date = timeline.date;
The cross join generates all the rows (the combinations of dates and stores). The left join brings in the revenue values for the store/dates that have them.

Average Group size per month Over previous ten years

I need to find the average size (average number of employees) of all the groups (employers) that we do business with per month for the last ten years.
So I have no problem getting the average group size for each month. For the Current month I can use the following:
Select count(*)
from Employees EE
join Employers ER on EE.employerid = ER.employerid
group by ER.EmployerName
This will give me a list of how many employees are in each group. I can then copy and paste the column into excel get the average for the current month.
For the previous month, I want exclude any employees that were added after that month. I have a query for this too:
Select count(*)
from Employees EE
join Employers ER on EE.employerid = ER.employerid
where EE.dateadded <= DATEADD(month, -1,GETDATE())
group by ER.EmployerName
That will exclude all employees that were added this month. I can continue to this all the way back ten years, but I know there is a better way to do this. I have no problem running this query 120 times, copying and pasting the results into excel to compute the average. However, I'd rather learn a more efficient way to do this.
Another Question, I can't do the following, anyone know a way around it:
Select avg(count(*))
Thanks in advance guys!!
Edit: Employees that have been terminated can be found like this. NULL are employees that are currently employed.
Select count(*)
from Employees EE
join Employers ER on EE.employerid = ER.employerid
join Gen_Info gne on gne.id = EE.newuserid
where EE.dateadded <= DATEADD(month, -1,GETDATE())
and (gne.TerminationDate is NULL OR gen.TerminationDate < DATEADD(day, -14,GETDATE())
group by ER.EmployerName
Are you after a query that shows the count by year and month they were added? if so this seems pretty straight forward.
this is using mySQL date functions Year & month.
Select AVG(cnt) FROM (
Select count(*) cnt, Year(dateAdded), Month(dateAdded)
from System_Users su
join system_Employers se on se.employerid = su.employerid
group by Year(dateAdded), Month(dateAdded)) B
The inner query counts and breaks out the counts by year and month We then wrap that in a query to show the avg.
--2nd attempt but I'm Brain FriDay'd out.
This uses a Common table Expression (CTE) to generate a set of data for the count by Year, Month of the employees, and then averages out by month.
if this isn't what your after, sample data w/ expected results would help better frame the question and I can making assumptions about what you need/want.
With CTE AS (
Select Year(dateAdded) YR , Month(DateAdded) MO, count(*) over (partition by Year(dateAdded), Month(dateAdded) order by DateAdded Asc) as RunningTotal
from System_Users su
join system_Employers se on se.employerid = su.employerid
Order by YR ASC, MO ASC)
Select avg(RunningTotal), mo from cte;

SQL/HSQLDB query and sub-query in Aggregate Function

My database looks like this (very simple) and is called "RideDate":
BikeDate Bike Miles
What I am looking to achieve is a query that for each month is a total(Sum) across all years, average(Avg) across all years, and a total for a specific year
(WHERE YEAR("Date")= '2014"). (I don"t have my exact code in front of me due to power fluctuations, pushing me onto an iPad (high winds and wet/heavy snow)).
My attempt goes something like this:
SElECT MONTH("BikeDate") AS "Month", SUM("Miles") AS "SMiles", AVG("AMiles") AS "Average",
(SELECT MONTH("BikeDate") SUM("Miles") WHERE YEAR("BikeDate") = '2014') AS "2014"
FROM "RideDate"
GROUP BY MONTH("BikeDate")
ORDER BY MONTH("BikeDate") ASC
The results should be:
(month) (sum of month over all years) (avg of month over all years) (sum of month for '14)
The last column will not collate by the 'group by month' and gives a sum for the whole year.
How can I write the sub-query to sum across the iterated month of the main query for the selected year? Is there another way of solving this?
You can try it with a CROSS JOIN
SELECT * FROM
(
(SELECT MONTH("BikeDate") AS "Month", SUM("Miles") AS "SMiles", AVG("AMiles") AS "Average",
FROM "RideDate"
GROUP BY MONTH("BikeDate"))a
CROSS JOIN
(SELECT SUM("Miles") as "YearSum"
FROM "RideDate"
WHERE YEAR("BikeDate") = '2014')b
) results