I have the following table of orders for users like the following:
CREATE TABLE orders (
order_id UUID,
user_id UUID,
date date,
order_type integer
);
I want to write SQL to do the following:
For every order want to compute the number of orders the user has within a previous week (7 days).
Write the following, but it counts the number of orders for each user but not for two levels of groupby.
SELECT order_id, user_id,
COUNT(order_id) OVER(PARTITION BY user_id ORDER BY date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) as num_orders_7days
FROM orders
You should use RANGE clause instead of ROWS with the proper date intervals:
SELECT order_id, user_id, date,
COUNT(order_id) OVER (
PARTITION BY user_id
ORDER BY date
RANGE BETWEEN INTERVAL 7 day PRECEDING AND INTERVAL 1 day PRECEDING
) as num_orders_7days
FROM orders;
See the demo.
Related
I'm having trouble coming up with a query to get the number of customers who purchased on multiple dates.
We're given a table of product purchases. Each row in the table represents an individual user product purchase.if the customer purchased two things on the same day that does not count as an upsell as they were purchased within a similar timeframe.
'transactions' table:
column
type
id
integer
user_id
integer
created_at
datetime
product_id
integer
quantity
integer
I tried in this way
select count(*)
from
( select user_id
, count(date)
from
( SELECT user_id
, DATE(created_at) AS date
FROM transactions
GROUP BY 1,2
) S
group
by 1
having count(date)>1
) A
I think you want:
SELECT COUNT(*)
FROM
(
SELECT user_id
FROM transactions
GROUP BY user_id
HAVING COUNT(DISTINCT DATE(created_at)) > 1
) t;
The subquery finds all users having transacted on more than one date, the outer query finds the count of such users.
Count the distinct dates per user, first, then count from table when the count is > 1.
See below:
WITH T as (select user_id,
count(distinct DATE(created_at)) as count
from transactions
GROUP BY user_id)
select count(*) from T where count > 1
I try to show the 'top 5' per month of worked hours.
I have the following query:
SELECT
concat(m.firstname, " ",m.lastname) AS name,
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(pl.end_activity,pl.start_activity)))) AS activity,
month(start_activity) AS month,
year(start_activity) AS year
FROM
log AS pl
INNER JOIN
employee AS m
ON
m.employee = pl.employee
GROUP BY
name,
year,
month,
ORDER BY
year,
month,
activity
I tried: limit 0,5 bit it gives me only the first 5 records of all. How can I show 5 records ordered by month?
In MySQL version 8.0.2 and above, we can utilize Window Functions. We can utilize Row_Number() window function to determine row numbers within a partition of concatenated expression of year and month. Ordering within the partition is done based on the descending order of activity.
We can then use this result-set as a Derived Table, and consider row number up-to 5. This will give us 5 rows per month, having top activity values.
SELECT dt.*
FROM
(
SELECT
concat(m.firstname, " ",m.lastname) AS name,
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(pl.end_activity,pl.start_activity)))) AS activity,
month(start_activity) AS month,
year(start_activity) AS year,
ROW_NUMBER() OVER (PARTITION BY CONCAT(year(start_activity), month(start_activity))
ORDER BY SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(pl.end_activity,pl.start_activity)))) DESC) AS row_no
FROM
log AS pl
INNER JOIN
employee AS m
ON
m.employee = pl.employee
GROUP BY
name,
year,
month
) AS dt
WHERE dt.row_no <= 5
ORDER BY
dt.year,
dt.month,
dt.activity
I want to get the first 4 rows with the highest value in a certain date range of a table in a mysql database. So I can do it with this code line, for example:
SELECT MONTH(date) as month, amount from sales where date >='2014-01-01' AND date <='2014-12-31' ORDER BY amount DESC LIMIT 4
But I want to add a new column with the percentage of each value, I tried with this line:
SELECT MONTH(date) as month, amount, round(amount*100/sum(amount) ,1) as 'percent' from sales where date >='2014-01-01' AND date <='2014-12-31' ORDER BY `amount` DESC LIMIT 4
But it doesn't work. How can I get it? I'd like some help.
Here's one way of doing it. Providing snippets of raw data also helps. Creating an sql fiddle helps even more!!
select month, amount, round(amount*100/total,1) as percent
from
(
select MONTH(date) as month, amount
from sales
where date >='2014-01-01' AND date <='2014-12-31'
ORDER BY amount DESC LIMIT 4
) c JOIN (
select sum(amount) as total
from sales
where date >='2014-01-01' AND date <='2014-12-31'
) t
I have a table that has a unique key each time a user creates a case:
id|doctor_id|created_dt
--|---------|-----------
1|23 |datetimestamp
2|23 |datetimestamp
3|17 |datetimestamp
How can I select and return the average amount of entries a user has per month?
I have tried this:
SELECT avg (id)
FROM `cases`
WHERE created_dt BETWEEN DATE_SUB(CURDATE(),INTERVAL 90 DAY) AND CURDATE()
and doctor_id = 17
But this returns a ridiculously large value that cannot be true.
To clarify: I am trying to get something like doctor id 17 has an average of 2 entries per month into this table.
I think you were thrown off by the idea of "averaging". You don't want the average id, or average user_id. You want the average number of entries into the table, so you would use COUNT():
SELECT count(id)/3 AS AverageMonthlyCases
FROM `cases`
WHERE created_dt BETWEEN DATE_SUB(CURDATE(),INTERVAL 90 DAY) AND CURDATE()
group by doctor_id
Since you have a 90 day interval, you want to count the number of rows per 30 days, or the count/3.
SELECT AVG(cnt), user_id
FROM (
SELECT COUNT(id) cnt, user_id
FROM cases
WHERE created_dt BETWEEN <yourDateInterval>
GROUP BY user_id, year(created_dt), month(created_dt)
)
Since you need average number of entries, AVG function is not really applicable, because it is SUM()/COUNT() and obviously you do not need that (why would you need SUM of ids).
You need something like this
SELECT
doctor_id,
DATE(created_dt,'%m-%Y') AS month,
COUNT(id) AS visits
FROM `cases`
GROUP BY
`doctor_id`,
DATE(created_dt,'%m-%Y')
ORDER BY
`doctor_id` ASC,
DATE(created_dt,'%m-%Y') ASC
To get visits per month per doctor. If you want to average it, you can then use something like
SELECT
doctor_id,
SUM(visits)/COUNT(month) AS `average`
FROM (
SELECT
doctor_id,
DATE(created_dt,'%m-%Y') AS month,
COUNT(id) AS visits
FROM `cases`
GROUP BY
`doctor_id`,
DATE(created_dt,'%m-%Y')
ORDER BY
`doctor_id` ASC,
DATE(created_dt,'%m-%Y') ASC
) t1
GROUP BY
doctor_id
Obviously you can add your WHERE clauses, as this query is compatible for multiple years (i.e. it will not count January of 2013th and January of 2014th as one month).
Also, it takes into account if a doctor has "blank" months, where he did not have any patients, so it will not count those months (0 can destroy and average).
Use this, you'll group each doctor's total id, by month.
Select monthname(created_dt), doctor_id, count(id) as total from cases group by 1,2 order by 1
Also you can use GROUP_CONCAT() as nested query in order to deploy a pivot like table, where each column is each doctor_id.
I am using PostgreSQL. I need to get the dates for the first 5 transactions of every user on my DB.
Transaction - trans.id, trans.date, trans.cust_id, trans.value
Customer - cust.id, cust.created_at
I need to get the date of the first 5 transactions for all the customers.
Try this query:
SELECT cust_id, date
FROM (
SELECT cust_id,
date,
row_number() OVER (partition by cust_id
ORDER BY date, id ) rn
FROM Transaction
) as alias
WHERE rn <= 5
ORDER BY 1,2
demo: http://sqlfiddle.com/#!15/cfd2e/4