Is it possible to do this in single query? - mysql

I have 2 tables, the first table:
And here's the 2nd table:
Desired Output:
Jan | 1,000,000
Feb | 0.000
Mar | 0.000
is it possible with single query ?

SELECT
t2.`month`,
SUM(t1.sales) as sales
FROM
table2 AS t2
LEFT JOIN table1 AS t1 ON t2.`month` = DATE_FORMAT(t1.date, "%b")
GROUP BY t2.`month`
ORDER BY sales desc
Hope this helps you.
But For this you have to make a little bit changes like in your table Your month name should be of 3 characters only , because we are joining the table name by the month name and as you can see in table there is a date added so we will convert it to the other format with 3 characters name using DATE_FORMAT(t1.date, "%b") , so it's gonna work for you
In case you dont want to use the 2nd table try this
SELECT DATE_FORMAT(t1.date, "%b") AS MONTH, SUM(t1.sales) FROM table1 AS t1 GROUP BY t1.date

SELECT s.Month, SUM(f.Sales)
FROM firstTable f, secondTable s
GROUP BY MONTH (Date)
should work for you.

Related

How to show months if it has no record and force it to zero if null on MySQL

i have an orders table, and i need to fetch the orders record by month. but i have terms if there is no data in a month it should still show the data but forcing to zero like this:
what i have done is using my query:
select sum(total) as total_orders, DATE_FORMAT(created_at, "%M") as date
from orders
where is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
group by DATE_FORMAT(created_at, "%m")
but the result is only fetched the existed data:
can anyone here help me to create the exactly query?
Thank you so much
Whenever you're trying to use a value that doesn't exist in the table, one option is to use a reference; whether it's from a table or a query-generated value.
I'm guessing that in terms of date data, the column created_at in table orders may have a complete list all the 12 months in a year regardless of which year.
Let's assume that the table data for orders spans from 2019 to present date. With that you can simply create a 12 months reference table for a LEFT JOIN operation. So:
SELECT MONTHNAME(created_at) mnt FROM orders GROUP BY MONTHNAME(created_at);
You can append that into your query like:
SELECT IFNULL(SUM(total),0) as total_orders, mnt
from (SELECT MONTHNAME(created_at) mnt FROM orders GROUP BY MONTHNAME(created_at)) mn
LEFT JOIN orders o
ON mn.mnt=MONTHNAME(created_at)
AND is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
GROUP BY mnt;
Apart from adding the 12 months sub-query and a LEFT JOIN, there are 3 other changes from your original query:
IFNULL() is added to the SUM() operation in SELECT to return 0 if the value is non-existent.
All the WHERE conditions has been switched to ON since remaining it as WHERE will make the LEFT JOIN becoming a normal JOIN.
GROUP BY is using the sub-query generated month (mnt) value instead.
Taking consideration of table orders might not have the full 12 months, you can generate it from query. There are a lot of ways of doing it but here I'm only going to show the UNION method that works with most MySQL version.
SELECT MONTHNAME(CONCAT_WS('-',YEAR(NOW()),mnt,'01')) dt
FROM
(SELECT 1 AS mnt UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION
SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12) mn
If you're using MariaDB version that supports SEQUENCE ENGINE, the same query above is much shorter:
SELECT MONTHNAME(CONCAT_WS('-',YEAR(NOW()),mnt,'01'))
FROM (SELECT seq AS mnt FROM seq_1_to_12) mn
I'm using MariaDB 10.5 in this demo fiddle however it seems like the month name ordering is based on the name value rather than the month itself so it looks un-ordered. It's in the correct order if it's in MySQL 8.0 fiddle though.
Thanks all for the answers & comments i really appreciate it.
i solved it by create table helper for static months then use union and aliasing, since i need the months in indonesia, i create case-when function too.
so, the query is like this:
SELECT total_orders,
(CASE date WHEN 01 THEN 'Januari'
WHEN 02 THEN 'Februari'
WHEN 03 THEN 'Maret'
WHEN 04 THEN 'April'
WHEN 05 THEN 'Mei'
WHEN 06 THEN 'Juni'
WHEN 07 THEN 'Juli'
WHEN 08 THEN 'Agustus'
WHEN 09 THEN 'September'
WHEN 10 THEN 'Oktober'
WHEN 11 THEN 'November'
WHEN 12 THEN 'Desember'
ELSE date END ) AS date
FROM (SELECT SUM(total) AS total_orders,
DATE_FORMAT(created_at, "%m") AS date
FROM orders
WHERE is_active = 1
AND tenant_id = 2
AND created_at like '%2021%'
GROUP BY DATE_FORMAT(created_at, "%m")
UNION
SELECT 0 AS total_orders,
code AS date
FROM quantum_default_months ) as Q
GROUP BY date
I still don't know if this query is fully correct or not, but I get my exact result.
cmiiw.
thanks all

How to select only entries that didn't repeat before a specific date?

My issue is that I'm stuck on making a select query where I need to select only items from latest 24 hours, that don't repeat themselves on entries before those 24 hours.
Here is a table:
name
date
Mark
2021-05-27
Jake
2021-05-27
Anthony
2021-05-27
Anthony
2021-05-26
Expected output:
name
Mark
Jake
Missing element: query
Help will be appreciated.
Edit: I know that's unprecise. The real table I'm using is with full datetime type. I'm going to test your answers today and then give response.
'24 hours' is unprecise, as you do not know which dates of yesterday are actually in range of the past 24 hours. If you are ok only with today's entries only (which are less), then the following would work:
SELECT name FROM demoTable GROUP BY name HAVING MIN(date) = CURRENT_DATE;
If you actually have date and time available, then you can have:
SELECT name FROM demoTable
GROUP BY name HAVING MIN(datetime) > DATEADD(day, -1, CURRENT_TIMESTAMP);
Depending on SQL dialect, DATEADD(...) might not be available, with e. g. SQLite you'd replace it by DATETIME('now', '-1 day').
Use the below query to get the last 24 data without duplicate name
select name from tabl1 where date>getdate()-1 group by name having count(name)>0
Here getdate()-1 will give the last 1 day difference i.e. 24hr
SELECT DISTINCT t1.name
FROM tablename t1
WHERE t1.`date` = CURRENT_DATE
AND NOT EXISTS ( SELECT NULL
FROM tablename t2
WHERE t1.name = t2.name
AND t2.`date` < CURRENT_DATE );

Combining These MySQL Queries and SUM data with one Query

I need to combine these two queries and get records using the single mySQL query.
Here are my queries
select DATE_FORMAT(campaign_date, '%Y-%m' ) AS month
, sum(sms)
from table1
group
by month
it returns me, sum of all months e.g
2019-05 5400
2019-06 3200
2019-07 11505
etc
I have another query which gets data in same format but from a different table.
select DATE_FORMAT(trans_date, '%Y-%m' ) AS month
, sum(camp_sms)
from table2
group
by month
2019-05 3500
2019-06 7256
2019-07 35465
etc
is it possible to combine these two query and get data same like this below:
Date sum(sms) sum(camp_sms)
2019-05 5400 3500
2019-06 3200 7256
2019-07 11505 35465
I have done this using PHP loops & array and to get the same output, but i want to do it using mySQL.
Simply use join
select t1.month, t1.total, t2.total from (
select DATE_FORMAT(campaign_date, '%Y-%m' ) AS month, sum(sms) total from table1 group by month
) t1
join (
select DATE_FORMAT(trans_date, '%Y-%m' ) AS month, sum(camp_sms) from table2 group by month
) t2 on t1.month = t2.month
If you don't want to skip any data from table1, then you should LEFT JOIN similarly you can use other joins according to your requirements.

Need help on MySQL query, i need to get the starting balance and the end balance by date group by stock_id

I need to get the starting balance from the earliest date and the ending balance from month end and group by stock_id.
My table:
id stock_id balance transact_at
1 1 100 2018-06-15
2 1 70 2018-06-16
3 1 30 2018-06-31
4 2 50 2018-06-01
5 2 10 2018-03-31
I want output:
stock_id start_balance ending_balance
1 100 30
2 50 10
Try this one. In this one two inner queries are fetching starting balance and closing balance by getting minimum and maximum transact_at corresponding to a stock_id and then the parent query is combing the two queries to get starting and closing balance in an single row. I have also shared fiddle link below to try.
select
tabledata1.stock_id,
startBalance,
closingBalance
from (
select
table1.stock_id,
balance as startBalance
from table1 join
(
select stock_id,
min(transact_at) as transact_at
from Table1 group by stock_id
) startTransaction
on Table1.stock_id = startTransaction.stock_id and
Table1.transact_at = startTransaction.transact_at
) tabledata1
join (
select
table1.stock_id,
balance as closingBalance
from table1 join
(
select stock_id,
max(transact_at) as transact_at
from Table1 group by stock_id
) endTransaction
on Table1.stock_id = endTransaction.stock_id
and Table1.transact_at = endTransaction.transact_at
) tabledata2
on tabledata1.stock_id = tabledata2.stock_id;
Demo
One approach in MySQL would be to aggregate by stock_id once and find the opening and closing dates. Then, self-join twice to pull in the actual balances which occurred on those opening and closing dates.
SELECT
t1.stock_id,
t2.balance AS start_balance,
t3.balance AS ending_balance
FROM
(
SELECT
stock_id,
MIN(transact_at) AS min_transact_at,
MAX(transact_at) AS max_transact_at
FROM my_table
GROUP BY stock_id
) t1
INNER JOIN my_table t2
ON t1.stock_id = t2.stock_id AND t2.transact_at = t1.min_transact_at
INNER JOIN my_table t3
ON t1.stock_id = t3.stock_id AND t3.transact_at = t1.max_transact_at;
Demo
Note: For posterity's sake, when MySQL 8+ becomes the norm, we could make use of things like ROW_NUMBER here, which might make it easier to get the result we want.
Try This One.
SELECT stock_id,MAX(balance) as start_balance, MIN(balance) as ending_balance FROM tbl_balance GROUP BY stock_id

GroupBy Query mysql

I have a table with values like the following
Name DatePurchased QuantityPurchased
A 2/3/2012 1
A 2/4/2012 1
A 2/5/2012 2
B 2/2/2012 1
B 2/3/2012 2
I want to output the following
Name DatePurchased QuantityPurchased
A 2/3/2012 1
A 2/4/2012 2 // as I have purchased 2 upto this date
A 2/5/2012 4 // as I have purchased 4 upto this date
B 2/2/2012 1
B 2/3/2012 3
My query
SELECT Name, `DatePurchased` , SUM(QuantityPurchased)
FROM table1
GROUP BY DatePurchased
does not do the math right. I know whats wrong but can't figure out the solution.
Thanks
Try:
SELECT t1.Name, t1.DatePurchased, SUM(t2.QuantityPurchased)
FROM table1 t1
LEFT JOIN table1 t2
ON t1.Name=t2.Name AND t1.DatePurchased >= t2.DatePurchased
GROUP BY Name, t1.DatePurchased
This joins table1 to itself within Name and such that t1s date is always at least t2s date, and sums up t2s QuantityPurchased (for each name,date in t1).
(Try performing the same query with SELECT *, and without the SUM and GROUP BY to see the joined table. Then the SUM and GROUP BY will become clear).
Rewriting the answer, misread it the first time. Now I understand that you want a running total. I believe something like this should work.
Select B.Name,B.DatePurchased,SUM(B.QuantityPurchased)
FROM Table1 AS A
INNER JOIN Table1 AS B
ON A.Name=B.Name AND B.DatePurchased <= A.DatePurchased
GROUP BY B.Name,B.DatePurchased
hope it helps!
SELECT Name, `DatePurchased` , SUM(QuantityPurchased)
FROM table1
GROUP BY Name, DatePurchased
ORDER BY Name, DatePurchased