Using grouped and non-grouped column in the same time - mysql

I have a table with payment requests.
PaymentId (UNSIGNED INT AI)
ClientId (USINGNED INT)
Amount (FLOAT)
PayTo (DATE)
Because for PayTo there are usually not more than 2-3 distinct values (per client) I want to create the list - how much money should be paid up to this day. Do I was looking for a query like this:
SELECT PayTo, SUM(IF(PayTo <= PayTo, Amount, 0)) as AmountThisDate
FROM Payments
WHERE ClientId='%d'
GROUP BY PayTo
ORDER BY PayTo DESC
But I'm 100% sure
PayTo <= PayTo
won't work.
What is the correct way to access GROUP BY Column and TABLE column at once if it is the same column?

It sounds like you want a cumulative sum. Here is a method using a correlated subquery:
SELECT p1.PayDate,
(select sum(p2.amount)
from Payments p2
where p2.ClientId = p.ClientId and
p2.PayDate <= p.PayDate
) as AmountThisDate
FROM Payments p1
WHERE p1.ClientId='%d'
GROUP BY p1.PayDate
ORDER BY p1.PayDate DESC;
Performance will be improved by having an index on payments(ClientId, PayDate, Amount).

SELECT PayDate, SUM(IF(PayDate <= current_date(), Amount, 0)) as AmountThisDate
FROM Payments
WHERE ClientId='%d'
GROUP BY PayDate
ORDER BY PayDate DESC
Is this what you were looking for?

Related

Avg function not returning proper value

I expect this query to give me the avg value from daily active users up to date and grouped by month (from Oct to December). But the result is 164K aprox when it should be 128K. Why avg is not working? Avg should be SUM of values / number of current month days up to today.
SELECT sq.month_year AS 'month_year', AVG(number)
FROM
(
SELECT CONCAT(MONTHNAME(date), "-", YEAR(DATE)) AS 'month_year', count(distinct id_user) AS number
FROM table1
WHERE date between '2020-10-01' and '2020-12-31 23:59:59'
GROUP BY EXTRACT(year_month FROM date)
) sq
GROUP BY 1
Ok guys thanks for your help. The problem was that on the subquery I was pulling the info by month and not by day. So I should pull the info by day there and group by month in the outer query. This finally worked:
SELECT sq.day_month, AVG(number)
FROM (SELECT date(date) AS day_month,
count(distinct id_user) AS number
FROM table_1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY 1
) sq
GROUP BY EXTRACT(year_month FROM day_month)
Do not use single quotes for column aliases!
SELECT sq.month_year, AVG(number)
FROM (SELECT CONCAT(MONTHNAME(date), '-', YEAR(DATE)) AS month_year,
count(distinct id_user) AS number
FROM table1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY month_year
) sq
GROUP BY 1;
Note the fixes to the query:
The GROUP BY uses the same columns as the SELECT. Your query should return an error (although it works in older versions of MySQL).
The date comparisons have been simplified.
No single quotes on column aliases.
Note that the outer query is not needed. I assume it is there just to illustrate the issue you are having.

mySQL query that is a bit tricky

Hi there I want to design this query in mySQL.
Statement: For all the customers that transacted during 2017, what % made another transaction within 30 days?
can you tell me how such query can be designed?
This is the picture of the table to perform this query on:
Table name is: transactions
Just use lead() to get the next date. Then aggregate at the customer level to determine if any transaction in the time period has another within 30 days for that customer.
Finally, aggregate again:
select avg(case when mindiff < 30 then 1.0 else 0 end) as within_30days
from (select customerid, min(datediff(next_date - date)) as mindiff
from (select t.*, lead(date) over (partition by customerid order by date) as next_date
from transactions t
) t
where date >= '2017-01-01' and date < '2018-01-01'
group by customerid
) c

SQL Query to get most recent date of transaction

New to SQL. Can someone please tell me if my SQL query is correct? I am trying to find out how much each unique customer spent on their most recent transaction.
Table Name: Expenditure
Columns:
1. created_time
2. customer_id
3. spend
SELECT
distinct(customer_id), sum(spend)
FROM
Expenditure
WHERE
created_time =
(SELECT MAX(created_time))
FROM
Expenditure
GROUP BY
distinct(customer_id)
If you are using MySQL 8+, then I prefer to use window functions here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY created_time DESC) rn
FROM Expenditure
)
SELECT customer_id, created_time, spend
FROM cte
WHERE rn = 1;
To correct the approach you were trying to use, you can correlate the subquery to the outer query by customer:
SELECT customer_id, created_time, spend
FROM expenditure e1
WHERE created_time = (SELECT MAX(e2.created_time)
FROM Expenditure
WHERE e2.customer_id = e1.customer_id);

How to Group a table and get results for a row based on the previous rows' data

I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;

I can't get mysql to return last row when using the aggregate MIN

I am using MIN function in mysql to return the smallest value of a column - lets call it price, however i also wish to display various other columns for this particular row with the smallest value for price. So far i have the following:
SELECT underlying,volatility FROM shares
where (id,price) IN (
SELECT id,MIN(price) FROM shares
where DATE(issueDate) >= DATE(NOW())
group by id
)
This almost works however it returns more than one row, i only wish to display the last row, can anyone please assist me with this?
i think i have solved the problem, it takes a while to execute so i will start by adding a new index :
SELECT underlying,volatility,price FROM shares
where (id,price) IN (
SELECT id,MIN(price) FROM shares
where DATE(issueDate) >= DATE(NOW())
group by id
) order by price asc limit 1;
SELECT underlying,volatility FROM shares
where (id,price) IN (
SELECT
SUBSTRING_INDEX(GROUP_CONCAT(id ORDER BY price ASC), ',', 1) AS id,
MIN(price) FROM shares
where DATE(issueDate) >= DATE(NOW())
group by id
)
Having clause will do the trick, please check my solution
select volatility,underlying, min(price) as min_price from shares
where DATE(issueDate) >= DATE(NOW())
group by issueDate
having min_price = min(price);
fiddle example