MySQL subquery returning multiple rows - mysql

SELECT CONCAT(MONTH(revenue_date),"/ ", YEAR(revenue_date)) as month_year,
(SELECT COUNT(DISTINCT DATE(delivery_date)) as operating_days
FROM table2 where weekday(delivery_date) <> 5 and
weekday(delivery_date) <> 6 and delivery_date < current_time and
year(delivery_date) > 2015 GROUP BY YEAR(delivery_date), MONTH(delivery_date)),
sum(revenue) as total_revenue,
from table1
where revenue_date < current_time and year(revenue_date) > 2015
group by year(revenue_date), month(revenue_date);
This shows the error "subquery returns more than 1 value". If I don't include group by in the subquery it returns just a total of all of the months but I need it to return it separately for all months.

Try this:
SELECT CONCAT(MONTH(revenue_date),"/ ", YEAR(revenue_date)) as month_year, a.operating_days
sum(revenue) as total_revenue,
from table2 JOIN
(SELECT YEAR(delivery_date) as `year`, MONTH(delivery_date) as `month`, COUNT(DISTINCT DATE(delivery_date)) as operating_days
FROM table2 where weekday(delivery_date) <> 5 and
weekday(delivery_date) <> 6 and delivery_date < current_time and
year(delivery_date) > 2015 GROUP BY YEAR(delivery_date), MONTH(delivery_date)) a
ON year(revenue_date) = a.year AND month(revenue_date) = a.month
where revenue_date < current_time and year(revenue_date) > 2015
group by year(revenue_date), month(revenue_date);

Join with the subquery.
SELECT DATE_FORMAT('%c/%Y', revenue_date) as month_year,
sum(revenue) as total_revenue, operating_days
from table1
JOIN (SELECT YEAR(delivery_date) AS delivery_year, MONTH(delivery_date) AS delivery_month,
COUNT(DISTINCT DATE(delivery_date)) as operating_days
FROM table2
where weekday(delivery_date) <> 5 and
weekday(delivery_date) <> 6 and delivery_date < current_time and
year(delivery_date) > 2015
GROUP BY delivery_year, delivery_month) AS t2
ON YEAR(revenue_date) = delivery_year AND MONTH(revenue_date) = delivery_month
where revenue_date < current_time
group by year(revenue_date), month(revenue_date);

Related

Calculate Ratio of two different SQL queries result that return numbers

I have Query 1
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) ) as x
Returns 18
Query 2
SELECT COUNT(DISTINCT user_id) total_daily_active_user_group_month FROM (SELECT user_id , MONTHNAME(time) mon , COUNT(*) cnt FROM ACTIVITIES
WHERE MONTH(time) = MONTH(NOW() - INTERVAL 1 MONTH) GROUP by user_id, MONTH(time) having cnt=31) as x
Return 6
I want the ratio of query 1 and two. Means
18/6 . I am using MySQL
If you use both queries as CTEs, then it becomes relatively simple:
WITH q1
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME))),
q2
AS (SELECT Count(DISTINCT user_id) total_daily_active_user_group_month
FROM (SELECT user_id,
Monthname(TIME) mon,
Count(*) cnt
FROM activities
WHERE Month(TIME) = Month(Now() - interval 1 month)
GROUP BY user_id,
Month(TIME)
HAVING cnt = 31))
SELECT q1.total_daily_active_user_group_month /
q2.total_daily_active_user_group_month
AS result
FROM dual;
You commented that you got an error pointing to the WITH keyword; switch to two subqueries, then; simplified:
select a.value / b.value as result
from (select count(distinct user_id) value
from ... your 1st query goes here
) a,
(select count(distinct user_id) value
from ... your 2nd query goes here
) b;

How to set default value from mysql join interval yearmonth

I have problem with my query. I have two tables and I want join them to get the results based on primary key on first table, but I missing 1 data from first table.
this my fiddle
as you can see, I missing "xx3" from month 1
I have tried to change left and right join but, the results stil same.
So as you can see I have to set coalesce(sum(b.sd_qty),0) as total, if no qty, set 0 as default.
You should cross join the table to the distinct dates also:
SELECT a.item_code,
COALESCE(SUM(b.sd_qty), 0) total,
DATE_FORMAT(d.sd_date, '%m-%Y') month_year
FROM item a
CROSS JOIN (
SELECT DISTINCT sd_date
FROM sales_details
WHERE sd_date >= '2020-04-01' - INTERVAL 3 MONTH AND sd_date < '2020-05-01'
) d
LEFT JOIN sales_details b
ON a.item_code = b.item_code AND b.sd_date = d.sd_date
GROUP BY month_year, a.item_code
ORDER BY month_year, a.item_code;
Or, for MySql 8.0+, with a recursive CTE that returns the starting dates of all the months that you want the results, which can be cross joined to the table:
WITH RECURSIVE dates AS (
SELECT '2020-04-01' - INTERVAL 3 MONTH AS sd_date
UNION ALL
SELECT sd_date + INTERVAL 1 MONTH
FROM dates
WHERE sd_date + INTERVAL 1 MONTH < '2020-05-01'
)
SELECT a.item_code,
COALESCE(SUM(b.sd_qty), 0) total,
DATE_FORMAT(d.sd_date, '%m-%Y') month_year
FROM item a CROSS JOIN dates d
LEFT JOIN sales_details b
ON a.item_code = b.item_code AND DATE_FORMAT(b.sd_date, '%m-%Y') = DATE_FORMAT(d.sd_date, '%m-%Y')
GROUP BY month_year, a.item_code
ORDER BY month_year, a.item_code;
See the demo.

MySQL - Count and GroupBy

I have this structure:
id| date_1 | date_2
---------------------
01|2017-01-01|2017-02-22
02|2017-01-02|2017-03-25
03|2017-02-10|2017-03-20
04|2017-03-11|2017-04-10
05|2017-03-15|2017-05-01
06|2017-03-20|2017-05-20
I would need this kind of result:
Month |Count(date_1)|Count(date_2)
---------------------------------
2017-01| 2 | 0
2017-02| 1 | 1
2017-03| 3 | 2
2017-04| 0 | 1
2017-05| 0 | 2
Now, I use this query (it works with only one date):
SELECT CONCAT(YEAR(date_1), '-', DATE_FORMAT(date_1,'%m')) AS month,
COUNT(*) AS items
FROM table
GROUP BY YEAR(date_1), MONTH(date_1)
ORDER BY date_1 DESC
You could union all the date values and then group and count them:
SELECT DATE_FORMAT(d, '%y-%m'), COUNT(*)
FROM (SELECT date_1 AS d FROM mytable
UNION ALL
SELECT date_2 FROM mytable) t
GROUP BY DATE_FORMAT(d, '%y-%m')
ORDER BY d DESC
To get the count of date_1 and date_2 in two different fields, with sub query:
SELECT DATE_FORMAT(temp1.d, '%y-%m'), COALESCE(d1count,0) AS date_1_count, COALESCE(d2count,0)AS date_2_count
FROM (
select date_1 as d from dates group by date_1
union all
select date_2 as d from dates group by date_2
) as temp1
LEFT JOIN (
select date_1, count(*) as d1count
from dates
group by DATE_FORMAT(date_1, '%y-%m')) as temp2
on DATE_FORMAT(temp2.date_1, '%y-%m') = DATE_FORMAT(temp1.d, '%y-%m')
LEFT JOIN (
select date_2, count(*) as d2count
from dates
group by DATE_FORMAT(date_2, '%y-%m')) as temp3
on DATE_FORMAT(temp3.date_2, '%y-%m') = DATE_FORMAT(temp1.d, '%y-%m')
GROUP BY DATE_FORMAT(temp1.d, '%y-%m')
Consider using subqueries behind SELECT
SELECT distinct DATE_FORMAT(t.d, '%y-%m'),
(
SELECT count(*)
FROM your_table as dd
where DATE_FORMAT(dd.date_1, '%y-%m') = DATE_FORMAT(t.d, '%y-%m')
) as count_date_1,
(
SELECT count(*)
FROM your_table as dd
WHERE DATE_FORMAT(dd.date_2, '%y-%m') = DATE_FORMAT(t.d, '%y-%m')
) as count_date_2
FROM
(
SELECT date_1 AS d FROM your_table
UNION ALL
SELECT date_2 as d FROM your_table
) as t
dbfiddle demo

MySQL Select, join, comparing dates fails

I have these two tables:
DateRanges
some_id start_date end_date
---------------------------------
1 2012-12-01 2012-12-15
1 2013-01-01 2013-01-15
3 2013-01-03 2013-01-10
Items
id name
----------------
1 Some name
2 Other name
3 So on...
What I try to achieve is to get, for each element in Items table, the biggest start_date (ignoring the smaller dates/date ranges for that Item) and check if the current date is in that range, like in the next table (let's say today's 02 January 2013):
id name TodayIsInTheRange
---------------------------------------------
1 Some name true
2 Other name false
3 So on... false
I have tried to obtain the 3rd table with the next query:
SELECT A.*, (B.`start_date` <= CURRENT_DATE AND CURRENT_DATE <= B.`end_date`) AS `TodayIsInTheRange`
FROM `Items` as A
LEFT JOIN `DateRanges` as B ON
A.id = B.some_id
SORT BY B.`end_date` DESC
But with this query my items repeat themselves because I have two records in DateRanges for the same item.
I use SQL Server, but I think something like this should be pretty close:
SELECT
I.Id,
I.Name,
(DR.start_date <= CURRENT_DATE AND CURRENT_DATE <= DR.end_date) AS `TodayIsInTheRange`
FROM `Items` AS I
LEFT JOIN
(SELECT Some_Id, MAX(Start_Date) as MaxStartDate
FROM `DateRanges`
GROUP BY Some_ID) AS HDR ON I.Id = HDR.Some_Id
LEFT JOIN `DateRanges` AS DR ON HDR.Some_Id = DR.Some_Id AND HDR.MaxStartDate = DR.Start_Date
select * from items join date_ranges dr0 on items.id = dr0.some_id
where start_date =
(select max(start_date) from date_ranges dr1 where dr0.some_id = dr1.some_id);
SELECT
a.*,
( b.start_date <= CURRENT_DATE
AND CURRENT_DATE <= b.end_date ) AS TodayIsInTheRange
FROM
Items AS a
LEFT JOIN
( SELECT some_id, MAX(start_date) AS start_date
FROM DateRanges
GROUP BY some_id
) AS m
JOIN
DateRanges AS b
ON b.some_id = m.some_id
ON a.id = m.some_id
ORDER BY b.end_date DESC ;
try to use GROUP BY and MAX function. The first provide you only one row for each item.id, the second tell you if there is at least one date in your range
SELECT A.*, MAX(B.`start_date` <= CURRENT_DATE AND CURRENT_DATE <= B.`end_date`) AS `TodayIsInTheRange`
FROM `Items` as A
LEFT JOIN `DateRanges` as B ON
A.id = B.some_id
GROUP BY A.id
ORDER BY B.`end_date` DESC

MySQL COUNT(*) GROUP BY HAVING COUNT=?

This my Query
SELECT COUNT(*) as total, toys, date FROM T1
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
UNION
SELECT COUNT(*) as total, toys, date FROM T2
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
UNION
SELECT COUNT(*) as total, toys, date FROM T3
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType
HAVING COUNT( total ) = 4
Output result
count Toys date
3 Bibi 2012-06-26
4 Baba 2012-06-26
How can i get MYSQL to show results only for count=4
SELECT * FROM (
SELECT COUNT(*) as total, toys, date FROM T1
WHERE (date >= '2012-06-26' AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType
UNION
SELECT COUNT(*) as total, toys, date FROM T2
WHERE (date >= '2012-06-26' AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType
UNION
SELECT COUNT(*) as total, toys, date FROM T3
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType) AS src
WHERE total = 4;
Please, note, that for proper data groupping you must have all columns either in the GROUP BY clause or as arguments to the aggregate functions. It is MySQL feature to allow you to avoid this restriction, but it might lead you to the unexpected results.
You need group by first then union the result.
SELECT COUNT(*) as total, toys, date FROM T1
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType HAVING COUNT( *) = 4
UNION
SELECT COUNT(*) as total, toys, date FROM T2
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType HAVING COUNT( * ) = 4
UNION
SELECT COUNT(*) as total, toys, date FROM T3
WHERE (date >= '2012-06-26'AND date < '2012-06-30') AND (Avail > '0')
GROUP BY RoomType HAVING COUNT( * ) = 4