How to get highest count from list data in mysql? - mysql

i have a query like this :
select DATE_FORMAT(o.created_at, '%Y-%m') as date,
JSON_EXTRACT(oi.inventory, '$.id') as inv_id,
count(JSON_EXTRACT(oi.inventory, '$.id')) as inv_count
from orders as o inner join order_items as oi on oi.order_id = o.id
where o.created_at >= (CURDATE() + INTERVAL (1 - DAY(CURDATE())) DAY) - INTERVAL 12 MONTH AND
o.created_at < (CURDATE() + INTERVAL (1 - DAY(CURDATE())) DAY) + INTERVAL 1 MONTH
group by date, inv_id
order by date desc limit 10
and the result is :
date
inv_id
inv_count
2023-01
1
22
2023-01
2
29
2022-12
1
1
2022-12
2
2
2022-11
1
2
2022-11
2
1
2022-10
1
2
2022-10
2
1
but all i want is result like this :
date
inv_id
inv_count
2023-01
2
29
2022-12
2
2
2022-11
1
2
2022-10
1
2
how to grouping data like that? because i can't use max(inv_count) inside group by

Related

How to retrieve data from previous 4 weeks (mySQL)

I am trying to write a query to get the last 4 weeks (Mon-Sun) of data. I want every week of data to be stored with an individual and shared table.
every week data store based on name if same name repeated on single week amt should sum and if multiple name it should be show data individual, To see an example of what I am looking for, I have included the desired input and output below.
this is my table
date
amt
name
2022-04-29
5
a
2022-04-28
10
b
2022-04-25
11
a
2022-04-23
15
b
2022-04-21
20
b
2022-04-16
20
a
2022-04-11
10
a
2022-04-10
5
b
2022-04-05
5
b
i want output like this
date
sum(amt)
name
2022-04-25 to 2020-04-29
16
a
2022-04-25 to 2020-04-29
10
b
2022-04-18 to 2022-04-24
35
b
2022-04-11 to 2022-04-17
30
a
2022-04-04 to 2022-04-10
10
b
I would appreciate any pointers or 'best-practises' which I should employ to achieve this task.
You can try to use DATE_ADD with WEEKDAY get week first day and end day.
SELECT
CASE WHEN
weekofyear(`date`) = weekofyear(NOW())
THEN 'current week'
ELSE
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d'))
END 'date',
SUM(amt)
FROM T
GROUP BY
CASE WHEN
weekofyear(`date`) = weekofyear(NOW())
THEN 'current week'
ELSE
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d'))
END
sqlfiddle
EDIT
I saw you edit your question, you can just add name in group by
SELECT
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d')) 'date',
SUM(amt),
name
FROM T
GROUP BY
CONCAT(date_format(DATE_ADD(`date`, interval - WEEKDAY(`date`) day), '%Y-%m-%d'),' to ',date_format(DATE_ADD(DATE_ADD(`date`, interval -WEEKDAY(`date`) day), interval 6 day), '%Y-%m-%d')),
name
ORDER BY 1 desc
sqlfiddle
This is in SQL Server, and just a mess about. Hopefully it can be of some help.
with cteWeekStarts
as
(
select
n,dateadd(week,-n,DATEADD(week, DATEDIFF(week, -1, getdate()), -1)) as START_DATE
from
(values (1),(2),(3),(4)) as t(n)
), cteStartDatesAndEndDates
as
(
select *,dateadd(day,-1,lead(c.start_date) over (order by c.n desc)) as END_DATE
from cteWeekStarts as c
)
,cteSalesSumByDate
as
(
select s.SalesDate,sum(s.salesvalue) as sum_amt from
tblSales as s
group by s.SalesDate
)
select c3.n as WeekNum,c3.START_DATE,isnull(c3.END_DATE,
dateadd(day,6,c3.start_date)) as END_DATE,
(select sum(c2.sum_amt) from cteSalesSumByDate as c2 where c2.SalesDate
between c3.START_DATE and c3.END_DATE) as AMT
from cteStartDatesAndEndDates as c3
order by c3.n desc

Get user who has transaction in last 7 days, and only one transaction in 30 days

I have a table like below, today is 2021-05-25.
UserId
TransactionDate
1
2021-05-21
1
2021-05-12
4
2021-05-25
1
2021-04-03
3
2021-05-15
3
2021-04-02
4
2021-03-25
I want the output is 4.
Since 1 has transaction within 7 days, but 2 transactions within 30days.
3 don't have any transaction within 7 days.
Only 4 has transaction within 7 days, and that's the only transaction within 30 days.
I can only filtered by the first condition using
WHERE t.TransactionDate > to_date('2021-05-17')
GROUP BY 1
Can anyone help how to apply both condition?
You can use aggregation with having:
select userid
from t
where transactiondate >= curdate() - interval 30 day
group by userid
having count(*) = 1 and
max(transactiondate) >= curdate() - interval 7 day;
If you want the transaction detail, it is a little more complciated:
select t.*
from transactions t
where t.transactiondate >= curdate() - interval 7 day and
not exists (select 1
from transactions t2
where t2.userid = t.userid and
t2.transactiondate >= curdate() - interval 30 day and
t2.transactiondate <> t.transactiondate
);

How to group by two fields?

I have the following table:
listId | accountId | amount
1 1 20
1 1 20
2 2 30
2 2 30
I need to SUM(amount) and group by listId, accountId to get result:
listId | accountId | amount |
1 1 40
2 2 60
But it does not work for me: SUM(amount) ... GROUP BY listId, accountId
My full query is:
select `account_transactions`.*,
`enterprise_invoces`.*,
ABS(SUM(IF(AT_amount>0, AT_amount, 0))) AS debit,
ABS(SUM(IF(AT_amount<0, AT_amount, 0))) AS credit
from `account_transactions`
inner join `enterprise_invoces`
on `enterprise_invoces`.`AC_id` = `account_transactions`.`AT_code`
where `AT_createuser` = 15 and
date(`AT_transactiondatetime`) >= 2019-04-11 and
date(`AT_transactiondatetime`) <= 2019-07-29 and
`AC_code` >= 601 and
`AC_code` <= 761
group by `enterprise_invoces`.`AC_id`, `account_transactions.AT_transactionficheno`
order by `AT_transactiondatetime` desc
Your select query should not have other columns and should have only the columns mentioned in group by and also the column which needs to be aggregated. So the query should be like this below.
select enterprise_invoces.AC_id, account_transactions.AT_transactionficheno ,
ABS(SUM(IF(AT_amount>0, AT_amount, 0))) AS debit,
ABS(SUM(IF(AT_amount<0, AT_amount, 0))) AS credit
from account_transactions
inner join enterprise_invoces
on enterprise_invoces.AC_id = account_transactions.AT_code
where AT_createuser = 15 and
date(AT_transactiondatetime) >= 2019-04-11 and
date(AT_transactiondatetime) <= 2019-07-29 and
AC_code >= 601 and
AC_code <= 761
group by enterprise_invoces.AC_id, account_transactions.AT_transactionficheno
order by AT_transactiondatetime desc

MYSQL Count with INNER JOIN not working

I have two tables
1) outreach
id profile_id url
-------------------------
1 2 www.test.com
2 3 www.google.com
3 4 www.example.com
4 2 www.test2.com
5 2 www.test3.com
6 2 www.test4.com
2). outreach_links
id outreach_id start_date created_at cost status
-----------------------------------------------------------------------
1 1 2016-12-01 00:00:00 2016-12-07 00:00:00 100.00 Approved
2 1 2016-12-02 00:00:00 2016-12-09 00:00:00 120.00 Approved
3 1 NUll 2016-12-28 00:00:00 20.00 Pending
4 1 2016-12-05 00:00:00 2016-12-10 00:00:00 35.00 Approved
5 1 2016-12-07 00:00:00 2016-12-13 00:00:00 10.00 Approved
6 2 2016-12-10 00:00:00 2016-12-15 00:00:00 10.00 Pending
7 2 2016-12-13 00:00:00 2016-12-18 00:00:00 10.00 Approved
8 2 2016-12-01 00:00:00 2016-12-28 00:00:00 10.00 Pending
9 2 2016-12-04 00:00:00 2016-12-21 00:00:00 10.00 Approved
10 2 2016-12-09 00:00:00 2016-12-22 00:00:00 15.00 Pending
I am trying to do a count by Month/Year and I thought its working but I think its not working because of "profile_id" issue here is my query:
select monthname(date) as Month, year(date) as Year, month(date) as Mn, UNIX_TIMESTAMP(CONCAT(year(date),"-",month(date),"-","01")) as tt,
(select count(*) from outreach_links where year(outreach_links.created_at) = year and month(outreach_links.created_at) = month and status = "Pending" and created_at>="2016-12-01 00:00:00" and created_at<="2016-12-31 00:00:00") as pp,
(select count(*) from outreach_links where year(outreach_links.start_date) = year and month(outreach_links.start_date) = month and status = "Approved" and start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00") as aa,
(select sum(cost) from outreach_links where year(outreach_links.start_date) = year and month(outreach_links.start_date) = month and status = "Approved" and start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00") as cc
from
(select year(outreach_links.created_at) as year, month(outreach_links.created_at) as month, outreach_links.created_at as date
from outreach_links
inner join outreach on outreach.id = outreach_links.outreach_id
where outreach_links.created_at>="2016-12-01 00:00:00" and outreach_links.created_at<="2016-12-31 00:00:00" and outreach.profile_id=2
union
select year(outreach_links.start_date) as year, month(outreach_links.start_date) as month, outreach_links.start_date as date
from outreach_links
inner join outreach on outreach.id = outreach_id
where start_date>="2016-12-01 00:00:00" and start_date<="2016-12-31 00:00:00" and outreach.profile_id=2 ) t1
group by year, month
order by date
So I am doing a date range from "2016-12-01 00:00:00" to "2016-12-31 00:00:00" these could be any date range inputed by the user , and try to do a count based on outreach.profile_id = 2 , my output is wrong its counting everything for all profile_ids, I am not sure why
Note: this is just a sample of the tables , there might be more records and the user inputed Date range from to could be different , I want to group them by Month / Year
here is my output: ( its counting ALL records)
array:1 [▼
0 => {#394 ▼
+"Month": "December"
+"Year": "2016"
+"Mn": "12"
+"tt": "1480568400.000000"
+"pp": "4"
+"aa": "6"
+"cc": "285.00"
}
]
Which is wrong it should count only for profile_id=2 , here is the DESIRED output I want:
array:1 [▼
0 => {#394 ▼
+"Month": "December"
+"Year": "2016"
+"Mn": "12"
+"tt": "1480568400.000000"
+"pp": "1"
+"aa": "4"
+"cc": "265.00"
}
]
As you can see the 3 counts are wrong they suppose to be:
"pp": "1"
"aa": "4"
"cc": "265.00"
here is what I am looking for:
1). **"pp" is Total Pending** Count when status="Pending" based on created_at
2). **"aa" is Total Approved** Count when status="Approved" based on start_date
3). **"cc" is Total Cost** Sum of All cost when Status="Approved" and based on start_date
4). Group by Month & Year of the user imputed Date Range
here is a SQLFIDDLE >> http://sqlfiddle.com/#!9/87dfa8/1
can you please help me fix it?
Thanks
I think you want something like this:
SELECT MONTHNAME(d.date) AS Month
, YEAR(d.date) AS Year
, MONTH(d.date) AS Mn
, SUM(IF(l.status = 'Pending' AND l.created_at >= d.date AND l.created_at < d.date + INTERVAL 1 MONTH ,1 ,0)) AS pp
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.date + INTERVAL 1 MONTH ,1 ,0)) AS aa
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.date + INTERVAL 1 MONTH ,l.cost,0)) AS cc
FROM ( SELECT '2016-12-01' + INTERVAL 0 MONTH AS date ) d
JOIN outreach o
ON o.profile_id = 2
LEFT
JOIN outreach_links l
ON l.outreach_id = o.id
AND ( ( l.start_date >= d.date + INTERVAL 0 MONTH
AND l.start_date < d.date + INTERVAL 1 MONTH
)
OR ( l.created_at >= d.date + INTERVAL 0 MONTH
AND l.created_at < d.date + INTERVAL 1 MONTH
)
)
GROUP BY d.date
EDIT
To specify the end date of the range along with the start date, the inline view d can return two date values. And the outer query can reference the second date value, in this example d.end_date, as well as the start of the range d.date.
SELECT MONTHNAME(d.date) AS Month
, YEAR(d.date) AS Year
, MONTH(d.date) AS Mn
, SUM(IF(l.status = 'Pending' AND l.created_at >= d.date AND l.created_at < d.end_date,1 ,0)) AS pp
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.end_date,1 ,0)) AS aa
, SUM(IF(l.status = 'Approved' AND l.start_date >= d.date AND l.start_date < d.end_date,l.cost,0)) AS cc
FROM ( SELECT '2016-12-01' + INTERVAL 0 MONTH AS date
, '2016-12-16' + INTERVAL 0 MONTH AS end_date
) d
JOIN outreach o
ON o.profile_id = 2
LEFT
JOIN outreach_links l
ON l.outreach_id = o.id
AND ( ( l.start_date >= d.date
AND l.start_date < d.end_date
)
OR ( l.created_at >= d.date
AND l.created_at < d.end_date
)
)
GROUP BY d.date, d.end_date

Getting data from the last 12 month using mysql

I have the following data structure in my table:
id member_from member_till
1 2014/03/01 2014/05/18
2 2014/01/09 2014/08/13
...
How can i get a count of active members for the last 12 month, grouped by month?
Ex:
...
2014/12/01,5
2015/01/01,12
As a future development is it possible to make the count the average of the first and last day of each month?
First of all you need the last twelve months. Then outer-join the members and count those where the month is in the membership range.
select
date_format(all_months.someday, '%Y %m') as mymonth,
count(membership.member_from) as members
from
(
select current_date as someday
union all
select date_add(current_date, interval -1 month)
union all
select date_add(current_date, interval -2 month)
union all
select date_add(current_date, interval -3 month)
union all
select date_add(current_date, interval -4 month)
union all
select date_add(current_date, interval -5 month)
union all
select date_add(current_date, interval -6 month)
union all
select date_add(current_date, interval -7 month)
union all
select date_add(current_date, interval -8 month)
union all
select date_add(current_date, interval -9 month)
union all
select date_add(current_date, interval -10 month)
union all
select date_add(current_date, interval -11 month)
) all_months
left join membership
on date_format(all_months.someday, '%Y %m')
between
date_format(membership.member_from, '%Y %m')
and
date_format(membership.member_till, '%Y %m')
group by date_format(all_months.someday, '%Y %m');
SQL fiddle: http://www.sqlfiddle.com/#!2/6dc5a/10.
As to your future requirement: You can join the membership table twice, once for the members on the first of a month, once for the last of the month (loosing those who participated only some days in the middle of a month). Then add both counts and divide by two.
You can try with SQL Query:
SELECT `member_from`, count(id) FROM tbl_test WHERE `member_from` BETWEEN <From date> AND <To date> GROUP BY `member_from`;
Complete with future requirement:
SELECT
d.ymonth,
COUNT(m.member_from) total,
COALESCE(SUM(d.fday BETWEEN m.member_from AND m.member_till), 0) total_fom,
COALESCE(SUM(d.lday BETWEEN m.member_from AND m.member_till), 0) total_lom
FROM
(
SELECT
CAST(#first_day := #first_day + INTERVAL 1 MONTH AS DATE) fday,
LAST_DAY(#first_day) lday,
DATE_FORMAT(#first_day, '%Y-%m') ymonth
FROM
information_schema.collations
CROSS JOIN
(SELECT #first_day := LAST_DAY(CURRENT_DATE) - INTERVAL 13 MONTH + INTERVAL 1 DAY) x
LIMIT 12
) d
LEFT JOIN
membership m
ON d.lday >= m.member_from
AND d.fday <= m.member_till
GROUP BY d.ymonth
The subquery generates a virtual lookup table with 3 columns:
+ ---------- + ---------- + ------- +
| fday | lday | ymonth |
+ ---------- + ---------- + ------- +
| 2014-02-01 | 2014-02-28 | 2014-02 |
| \/ | \/ | \/ |
| 2015-01-01 | 2015-01-31 | 2015-01 |
+ ---------- + ---------- + ------- +
Then the membership table can be joined on the overlaps member_from-member_till and the beginning and ending of each month.

Categories