count not working inside group_concat Mysql - mysql

I am trying to concat count of id and 1 inside group_concat. Below is my query.
MYSQL:
SELECT
months.name AS NAME,
CONCAT(
'[',
GROUP_CONCAT(
CONCAT(
'[\"',
COUNT(p_c_n_details.JPN_ID),
'\",',
1,
']'
)
),
']'
) AS DATA
FROM
p_c_n_details
INNER JOIN in_e_s_s__p_c_ns RIGHT OUTER JOIN months ON months.id =
MONTH(p_c_n_details.created_at) AND p_c_n_details.type IN('Process Change',
'Design Change') AND p_c_n_details.JPN_ID =
in_e_s_s__p_c_ns.juniperinternalpcnid AND p_c_n_details.created_at >=
last_day(NOW()) + INTERVAL 1 DAY - INTERVAL 3 MONTH
WHERE
months.name IN(
MONTHNAME(
DATE_SUB(CURDATE(), INTERVAL 0 MONTH)),
MONTHNAME(
DATE_SUB(CURDATE(), INTERVAL 1 MONTH)),
MONTHNAME(
DATE_SUB(CURDATE(), INTERVAL 2 MONTH))
)
GROUP BY
months.id
Expected Output:
Name | DATA
-------------------------
July [20,1]
August [33,1]
Table months contains month names.
But I am getting error #1111 - Invalid use of group function. I tried this link
mysql group_concat with a count inside?
but I am facing error when using in my query.

This is a guess.
Try:
SELECT months.name AS NAME,
CONCAT('{',COUNT(p_c_n_details.JPN_ID),',1}' AS DATA
in place of the SELECT you now have.
Your example result doesn't show a need for GROUP_CONCAT().

Related

I need help putting two select query's into one stored procedure for one output?

I tried a union and union all but I get an error incorrect usage of union.
select sr.shipper_city,
sr.consignee_site_city,
cast((avg(round((to_seconds(sr.delv_live_start)- to_seconds(sr.pick_depart_loaded))/(60*60*24),1))) as decimal) as TransitDays90
from cs.shipment_reporting sr
where customer_id = '15619'
and (pick_depart_loaded >(NOW() - INTERVAL 3 MONTH))
group by sr.shipper_city,sr.consignee_site_city
order by sr.shipper_city,sr.consignee_site_city
select sr.shipper_city,
sr.consignee_site_city,
(cast((avg(round((to_seconds(sr.delv_live_start)- to_seconds(sr.pick_depart_loaded))/(60*60*24),1))) as decimal)) as TransitDays30
from cs.shipment_reporting sr
where sr.customer_id = '15619' and (sr.pick_depart_loaded >(NOW() - INTERVAL 1 MONTH))
group by sr.shipper_city,sr.consignee_site_city
order by sr.shipper_city,sr.consignee_site_city
Do the order by in outer query, try:
select shipper_city,consignee_site_city,TransitDays90
from (
select sr.shipper_city,
sr.consignee_site_city,
cast((avg(round((to_seconds(sr.delv_live_start)- to_seconds(sr.pick_depart_loaded))/(60*60*24),1))) as decimal) as TransitDays90
from cs.shipment_reporting sr
where customer_id = '15619'
and (pick_depart_loaded >(NOW() - INTERVAL 3 MONTH))
group by sr.shipper_city,sr.consignee_site_city
---- removed order by , it has no effect
UNION
select sr.shipper_city,
sr.consignee_site_city,
(cast((avg(round((to_seconds(sr.delv_live_start)- to_seconds(sr.pick_depart_loaded))/(60*60*24),1))) as decimal)) as TransitDays30
from cs.shipment_reporting sr
where sr.customer_id = '15619' and (sr.pick_depart_loaded >(NOW() - INTERVAL 1 MONTH))
group by sr.shipper_city,sr.consignee_site_city
) as t1
order by shipper_city , consignee_site_city ;
Your queries have different column names: TransitDays90 and TransitDays30.
Based on your demands, you can either change them to the same or add NULL columns to each query, but make sure that order and number of columns is same in each query

How to get the last 30 days results with MySQL with 0 value too?

I'm trying to get all my result of last 30 days, getting 0 when the count is 0.
My query is:
SELECT substring(mc.publication_date, 1, 10) AS title, count(mc.id) AS quantity
FROM mymyv_cards mc
WHERE mc.publicated = 1 AND STR_TO_DATE(substring(mc.publication_date, 1, 10), "%d-%m-%Y") BETWEEN CURDATE() - INTERVAL 30 DAY AND CURDATE()
GROUP BY substring(mc.publication_date, 1, 10)
And I get this:
But I would like the result was like:
06-04-2021 --> 1
07-04-2021 --> 2
08-04-2021 --> 0
09-04-2021 --> 0
10-04-2021 --> 0
............... etc etc
I don't know how to do that, can you help me?
What you need is a list of all the dates. If you don't have one handy, you can create on using a recursive CTE:
with recursive dates as (
select curdate() as dte, 1 as lev
union all
select dte - interval 1 day, lev + 1
from dates
where lev < 30
)
select *
from dates;
Then you incorporate this into your query with a left join:
with recursive dates as (
select curdate() as dte, 1 as lev
union all
select dte - interval 1 day, lev + 1
from dates
where lev < 30
)
select d.dte, count(mc.id)
from dates d left join
mymyv_cards mc
on mc.publicated = 1 and
str_to_date(left(mc.publication_date, 10), '%d-%m-%Y') >= d.dte and
str_to_date(left(mc.publication_date, 10), '%d-%m-%Y') < d.dte + interval 1 day
group by d.dte;
Note that a column called publication_date should be stored with the value as a date not as a string. You should really fix the data model so the data is stored using the correct types.
Also, you might have a numbers table or calendar table lying around in your database. If so, you can use that instead of the recursive CTE.

Add months in db date using interval in mysql

I want to add month in transaction date using mysql interval function by join plan table and transaction table,however this method not working but If I add months in static way to transaction date it is working.
plan table:
plan_id plan
1 6 month
2 12 month
3 3 month
transaction table:
id user_id subscribed_on plan_id
1 2 2020-04-04 1
2 4 2019-02-22 2
Mysql query (not working):
SELECT t.* FROM transaction t inner join plan p on p.plan_id=t.plan_id
where t.user_id=2 and DATE_ADD(date(t.subscribed_on), INTERVAL p.plan) >= CURDATE()
order by t.id desc
If I add month in static way than it is working fine:
SELECT t.* FROM transaction t inner join plan p on p.plan_id=t.plan_id
where t.user_id=2 and DATE_ADD(date(t.subscribed_on),
INTERVAL 6 month) >= CURDATE()
order by t.id desc
MySQL does not support using interval that way. Unlike in other databaes (such as Postgres for example), the unit argument is a keyword, not a literal string.
I would suspect that your table may store other intervals than just months (say, years, days, and so on). If so, you can use string functions and a case expression to accommodate the different possible values, like:
select t.*
from transaction t
inner join plan p on p.plan_id = t.plan_id
where
t.user_id = 2
and date(t.subscribed_on) + case substring_index(p.plan, ' ', -1)
when 'year' then interval substring_index(p.plan, ' ', 1) year
when 'month' then interval substring_index(p.plan, ' ', 1) month
when 'day' then interval substring_index(p.plan, ' ', 1) day
end
>= current_date
order by t.id desc
The logic here is to split the stored interval string into two parts: the number, and the unit; the case expression processes the unit and generate the proper literal interval accordingly.
Unfortunately a string in the data is not equivalent to an interval. One method is:
date(t.subscribed_on) + interval substring_index(plan, ' ') + 0 month
Note here that month is a keyword, not a string.
Try to force the plan column in the plan table to be an integer. Does not seem to be possible to cast a string to an interval.
I tried like so:
WITH
plan( plan_id,plan) AS (
SELECT 1,'6 month'
UNION ALL SELECT 2,'12 month'
UNION ALL SELECT 3,'3 month'
)
,
transaction(id,user_id,subscribed_on,plan_id) AS (
SELECT 1,2,DATE '2020-09-04',1
UNION ALL SELECT 2,4,DATE '2019-02-22',2
)
SELECT t.*
FROM transaction t
INNER JOIN plan p ON p.plan_id = t.plan_id
WHERE t.user_id = 2
AND DATE_ADD(
DATE(t.subscribed_on)
, INTERVAL CAST(REPLACE(plan,' month','') AS SIGNED) MONTH
) >= CURDATE()
ORDER BY t.id DESC
(returns no results, as you don't have any dates high enough in your example data...)

Combine two select statements grouped by date returning two columns of data

This seems like an easy task but my basic sql knowledge is failing me as I'm still learning.
Basically, I'm trying to combine:
SELECT DATE(created) DATE, COUNT(DISTINCT created) newpost FROM surveys
WHERE created >= Last_day(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND created < last_day(CURRENT_DATE) + INTERVAL 1 DAY GROUP BY DATE(created);
and
SELECT DATE(TIMESTAMP) DATE,subs FROM trafficstats
WHERE TIMESTAMP >= LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND TIMESTAMP < LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY;
into one query that will return data, grouped by date, into two additional columns - newposts and subs.
I've tried using UNION, which doesn't seem to be giving me the output I want. It combined the data into one column (newpost), and also didn't group by date.
I'm still fairly new to writing MySQL queries, and I've tried searching for answers to no avail. Hoping to seek the knowledge of those smarter than me here.
You could use JOIN
select t1.DATE, t1.newpost, t2.subs
from (
SELECT DATE(created) DATE, COUNT(DISTINCT created) newpost
FROM surveys
WHERE created >= Last_day(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND created < last_day(CURRENT_DATE) + INTERVAL 1 DAY
GROUP BY DATE(created)
) t1
left join (
SELECT DATE(TIMESTAMP) DATE, subs
FROM trafficstats
WHERE TIMESTAMP >= LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND TIMESTAMP < LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY
) t2 on t1.DATE = t2.DATE
I guess you want one row per distinct date, with two different count values shown.
This kind of query is slightly tricker than it seems at first glance, because the two summary queries might have different sets of dates.
So you need to start with a subquery that yields all possible dates of interest. You then need to LEFT JOIN each summary query to it. You must use LEFT JOIN instead of the ordinary inner JOIN, because LEFT JOIN doesn't suppress rows from the right side of the join when they don't match any rows from the left side.
Here goes:
All your dates. Notice the UNION operation is a setwise (duplicate-removing) union operation.
SELECT DISTINCT DATE(created) DATE FROM newpost
WHERE created >= Last_day(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND created < last_day(CURRENT_DATE) + INTERVAL 1 DAY
UNION
SELECT DISTINCT DATE(TIMESTAMP) DATE FROM trafficstats
WHERE TIMESTAMP >= LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND TIMESTAMP < LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY
Then you need your two summary subqueries. The first one is this. Notice that I changed COUNT(DISTINCT created) to COUNT(*) because I don't understand the logic behind the DISTINCT there. Can you have more than one row for a single post; do you tell them apart by timestamp? If you have a row for each post you should COUNT(*).
SELECT DATE(created), COUNT(*) newposts
FROM newpost
GROUP BY DATE(created)
The second summary is this. Again, I counted rows.
SELECT DATE(TIMESTAMP), COUNT(*) subs
FROM trafficstats
GROUP BY DATE(TIMESTAMP)
Finally, join those three subqueries like so. You get the dates from the first subquery, and the summary-by-date information from the second two subqueries.
SELECT dates.DATE, posts.newposts, subs.subs
FROM ( /* date subquery */ ) dates
LEFT JOIN ( /* posts subquery */ ) posts ON dates.DATE = posts.DATE
LEFT JOIN ( /* subs subquery */ ) subs ON dates.DATE = subs.DATE
ORDER BY dates.DATE
Putting it all together:
SELECT dates.DATE, posts.newposts, subs.subs
FROM (
SELECT DISTINCT DATE(created) DATE FROM newpost
WHERE created >= Last_day(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND created < last_day(CURRENT_DATE) + INTERVAL 1 DAY
UNION
SELECT DATE(TIMESTAMP) DATE FROM trafficstats
WHERE TIMESTAMP >= LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH
AND TIMESTAMP < LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY
) dates
LEFT JOIN (
SELECT DATE(created), COUNT(*) newposts
FROM newpost
GROUP BY DATE(created)
) posts ON dates.DATE = posts.DATE
LEFT JOIN (
SELECT DATE(TIMESTAMP), COUNT(*) subs
FROM trafficstats
GROUP BY DATE(TIMESTAMP)
) subs ON dates.DATE = subs.DATE
ORDER BY dates.DATE

Mysql sum of records by month for the last 12 months

Hello I'm using this sql query to get the last 12 month records based on month for chart representation:
SELECT DATE_FORMAT(drives.timestamp, "%b") AS Month,
DATE_FORMAT(drives.timestamp, "%d-%m-%Y %H:%i:%s") AS Exact_date,
drives.departure,
drives.destination,
drives.route,
CONCAT(drivers.name, " ", drivers.surname) as driver,
drivers.id as driver_id
FROM drives, drivers WHERE drives.driver = drivers.id
AND drives.timestamp > DATE_SUB(now(), INTERVAL 12 MONTH) ORDER BY drives.timestamp Asc
however if there are no records for a month it is not included in the result set as expected, and I'm doing a lot of calculations with php to accomplish what I want.
My question is this: Is there a way to retrieve a simple result set with the sum of drives of each month for the last 12 months AND if there are 0 drives for a month it must be also included-shown in the result set.
You need to do an outer join with a table that contains a row for each month. Assuming you don't have such a table, you can create it on the fly with a hard-coded UNION query:
SELECT * FROM
(SELECT DATE_FORMAT(now(), "%b") as Month
UNION
SELECT DATE_FORMAT(now() - INTERVAL 1 MONTH), "%b")
UNION
SELECT DATE_FORMAT(now() - INTERVAL 2 MONTH), "%b")
UNION
...
SELECT DATE_FORMAT(now() - INTERVAL 11 MONTH), "%b")) AS Months
LEFT JOIN (SELECT DATE_FORMAT(drives.timestamp, "%b") AS Month,
drives.timestamp,
DATE_FORMAT(drives.timestamp, "%d-%m-%Y %H:%i:%s") AS Exact_date,
drives.departure,
drives.destination,
drives.route,
CONCAT(drivers.name, " ", drivers.surname) as driver,
drivers.id as driver_id
FROM drives, drivers WHERE drives.driver = drivers.id
AND drives.timestamp > DATE_SUB(now(), INTERVAL 12 MONTH)) data
ON Months.Month = data.Month
ORDER BY data.timestamp
Any months with no records will have one row with NULL in the data columns.