mySQL convert string date to quarter - mysql

I have several fields in a sql table, including name, type, and date. In date, it is stored as a string "2016-05-01" format. I would like to count the number of occurrences of name grouped by each quarter date.
By this, I mean that name can occur multiple times in a month. I would like to count the number of times the names occur in groups of 3 months (quarters) and print the name, count, and quarter in each row.
So if for example I had the columns name, type, and date and ran the query
it could result in
Name Quarter Count
Ron | 1 | 62 |
Ron | 2 | 32 |
Ron | 3 | 45 |
Ron | 4 | 33 |
Tim | 1 | 62 |
Tim | 3 | 62 |
and so on. Thanks

Assuming that my_date_column is a date
You can use quarter()
select Name, QUARTER(my_date_column), count(*)
frpm my_table
group by name, QUARTER(my_date_column)
;
otherwise you should convert the string in date
for convert a string you can use
str_to_date('2016-09-20', '%Y-%m-%d')
select Name, QUARTER(str_to_date(my_strdate_column, '%Y-%m-%d')), count(*)
frpm my_table
group by name, QUARTER(str_to_date(my_strdate_column, '%Y-%m-%d'))
;

Related

Count unrepeated elements on mysql group by

I have the following table:
| id | metrictimestamp | vehicleid |
+----+-----------------+-----------+
| 1 | 20180201025934 | 33089 |
| 2 | 20180201025955 | 34489 |
| 3 | 20180201025959 | 32040 |
I need to group by date(metrictimestamp) and count how many unrepeated "vehicleid" there is for each day, any sugestions?
You can use DISTINCT in your query:
SELECT COUNT(DISTINCT metrictimestamp) FROM yourTable
First you need to convert your metrictimestamp field into a date type that mysql understands:
STR_TO_DATE(metrictimestamp, '%Y%m%d%h%i%s')
next you need to extract the date portion of that field and give it an alias (date):
DATE(STR_TO_DATE(metrictimestamp, '%Y%m%d%h%i%s')) date
finally you need to group by the resultant date and the vehicleid and filter by repeated records (so only include singletons), so putting it all together:
select DATE(STR_TO_DATE(metrictimestamp, '%Y%m%d%h%i%s')) date, vehicleid from group_test_table group by date, vehicleid having count(vehicleid) = 1;
If I misunderstood your question and you only want the unique vehicleids for any date then:
select distinct DATE(STR_TO_DATE(metrictimestamp, '%Y%m%d%h%i%s')) date, vehicleid from group_test_table group by date, vehicleid;

How do I select from MySQL all rows that fall within a month but may have dates in the next month?

I have a table that looks kind of like this;
ID | netID | indate | outdate | name | org
=====================================================================
1 | 50 | 2020-03-31 23:50 | 2020-03-31 23:32 | Bill | orgA
2 | 50 | 2020-03-31 23:51 | 2020-03-31 23:32 | Fred | orgA
3 | 50 | 2020-04-01 00:02 | 2020-04-01 00:05 | Sam | orgA
4 | 51 | 2020-03-31 23:50 | 2020-03-31 23:32 | Harry | orgB
5 | 51 | 2020-03-31 23:51 | 2020-03-31 23:32 | George | orgB
6 | 51 | 2020-04-01 00:02 | 2020-04-01 00:05 | Tom | orgB
I need to write a report by org & year & month, but any row that has the same netID must be included even if it its in a different year or month. And I can't say "WHERE netID = 50" for example because I don't know what netID's are in the month '03' of the year '2020'.
I'm looking for the first three rows to be returned if I need a March 2020 report for orgA.
Below doesn't work for what I need, and I can't figure out how to get all of the rows for each netID regardless of month. Can someone please give me an example of how to retrieve them?
SELECT date(iodate) as logdate,
Name,
netID,
COALESCE( netID, 'Month Total') AS netTTL,
COUNT(ID) AS idCount,
month(logdate AS month
FROM table
WHERE org = 'orgA'
AND year(indate) = '2020'
AND month(iodate) = '03'
GROUP BY year(logdate), month, netID WITH ROLLUP
One method to get all rows where any row exists, that has the same net ID, the requested organization and a date in the requested range is getting the net IDs for the range and organization in a derived table and then join the table.
SELECT t1.*
FROM (SELECT DISTINCT
t2.netid
FROM elbat t2
WHERE t2.org = 'orgA'
AND t2.indate >= '2020-03-01'
AND t2.indate < '2020-04-01') x
INNER JOIN elbat t1
ON t1.netid = x.netid;
A few notes:
You should use range expressions rather than applying year() and month() to the date in the WHERE clause. Range expressions can use indexes and speed up the query.
In your query you have columns/expressions that are neither applied to an aggregation function nor in the GROUP BY. Though older or badly configured MySQL servers accept that, it may produce funny results. But since you didn't further explain what you want to do there, there's not much more to say here than "You're doing it wrong!".

SQL count row equal to column

Here is my table:
+--------+---------------------+
| roomNo | date |
+--------+---------------------+
| 1 | 2017-05-17 16:05:00 |
| 1 | 2017-05-17 15:05:00 |
| 2 | 2019-05-20 12:30:00 |
| 2 | 2019-05-15 10:30:00 |
| 2 | 2019-05-14 08:00:00 |
+--------+---------------------+
I want to get the day where the room is used at least once and which day(s) had the most operations in it and how many times, in the current year. I don't know how to compare the dates.
The expected result would be something like :
+--------+------------+------------+
| roomNo | date | operations |
+--------+------------+------------+
| 2 | 2019-05-20 | 3 |
+--------+------------+------------+
We can use MySQL DATE function to lop off times from DATETIME and TIMESTAMP columns. Or we could use MySQL DATE_FORMAT function, to return just year, month day.
We can use an aggregate function like COUNT or SUM in a query with GROUP BY to get counts by room and day.
If "current year" means from Jan 1 thru Dec 31, we can use expression to derive date values of '2019-01-01' and '2020-01-01', and do a comparison of the date column to those values in the WHERE clause.
As a start, consider this:
SELECT t.roomno
, DATE(t.date) AS date_
, COUNT(*) AS cnt_
FROM mytable t
WHERE t.date >= DATE_FORMAT(NOW(),'%Y-01-01') + INTERVAL 0 YEAR
AND t.date < DATE_FORMAT(NOW(),'%Y-01-01') + INTERVAL 1 YEAR
GROUP
BY t.roomno
, DATE(t.date)
ORDER
BY t.roomno
, cnt_ DESC
If the goal is to just return one of the rooms that has the highest number of uses, we could use a LIMIT clause, and order by the highest count to lowest,
ORDER
BY cnt_ DESC
, t.roomno
LIMIT 1
If the results are more complex than that, we can omit the LIMIT clause, and use the result from that query as an inline view in an outer query.
With MySQL 8.0, we can use common table expression (CTE) and window/analytic functions, to get more elaborate results.

How to group same table differently in outer query and subquery

Table looks like this:
id | number | provider| datetime | keyword|country|
1 | 1 | Mobitel |2012-11-05| JAM | RS |
2 | 2 | Telekom |2013-04-25| ASTRO| RS |
3 | 1 | Si.Mobil|2013-04-27| DOMACE| BA |
4 | 4 | Telenor |2013-04-21| BIP | HR |
5 | 7 | VIP |2013-04-18| WIN | CZ |
6 | 13 | VIP |2014-05-21| DOMACE| RS |
7 | 5 | VIP |2014-06-04| WIN | HU |
I need to sum all numbers grouped by keyword and country and to sum all numbers again grouped by keyword, country and provider all in one query.
Here is how I tried to do it:
SELECT (SELECT SUM(number),country, keyword
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword )
num_of_all_subs,
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
But this query throws an error:
#1241 - Operand should contain 1 column(s)
Here is what I expect to get:
id | num_of_all_subs|num_of_subs | provider| datetime | keyword|country|
1 | 19 | 4 | Mobitel |2012-11-05| JAM | RS |
2 | 12 | 5 |Telekom |2013-04-25| ASTRO| RS |
3 | 18 | 1 |Si.Mobil |2013-04-27| DOMACE| BA |
4 | 42 | 21 |Telenor |2013-04-21| BIP | HR |
5 | 76 | 23 |VIP |2013-04-18| WIN | CZ |
6 | 13 | 3 |VIP |2014-05-21| DOMACE| RS |
7 | 53 | 11 |VIP |2014-06-04| WIN | HU |
Field num_of_all_subs meaning that sum of all numbers for lets say JAM(keyword) and RS(country) is 19 , but per Mobitel(provider) is num_of_subs 4 from all 19, since there are other providers for that country and keyword(even though they are not displayed in table schema).
Please help me to extract this data, since I'm stuck.
Your subquery for num_of_all_subs (which is a single number) must only return one column and, next problem, one row. Also, this subquery will be evaluated before you group, while you actually want to first group and get the columns num_of_subs, country, keyword and provider, and, afterwards, add another column num_of_all_subs to that first resultset.
You can do this exactly as just described: first get the grouped subquery (here called details), then use a dependent subquery to get, for each row in that subquery, the value for num_of_all_subs by looking at the table (again) and sum over all rows that have the same provider and country:
SELECT
(SELECT SUM(number)
FROM daily_subscriptions ds
WHERE datetime >= '2016-02-01 23:59:59'
and ds.country = details.country
and ds.keyword = details.keyword
) as num_of_all_subs,
details.*
from
(select
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
) as details;
An alternative would be to do calculate both groups seperately, one including provider (details), and one without (all_subs). One will contain num_of_subs, one will contain num_of_all_subs. The you can combine (join) these two queries when they have the same country and keyword:
SELECT
all_subs.num_of_all_subs,
details.*
from
(select
SUM(number) as num_of_subs,
country,
keyword,
provider
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword, provider
) as details
left join
(SELECT
SUM(number) as num_of_all_subs,
country,
keyword
FROM daily_subscriptions
WHERE datetime >= '2016-02-01 23:59:59'
GROUP BY country, keyword
) as all_subs
on all_subs.keyword = details.keyword and all_subs.country = details.country;
In your case, you can use a join instead of a left join, because every row in the first subquery will have a row in the second subquery, although it's usually the safer way do keep it.
While in theory, MySQL could execute these queries identically (and for less complicated queries, it will actually optimize and treat, whenever possible and useful, dependent subqueries like joins), in current MySQL versions this will most likely not be the case and the 2nd option is probably faster. Anyway, for both versions, a composite index on (country, keyword, provider) will do wonders.

Query to Find Duplicate entries

I am looking for an SQL query to give me a list of duplicate entries in a table. However, there are 3 different columns to take into account. First is an ID, Second is a Name, and third is a Date. The situation is that there are multiple Names that are assigned with the same ID, and there are multiple records of those in a day, which makes THOUSANDS of different records per day.
I already filtered it so that only results for the past 7 days will show, but the amount of records is still too much for me to extract. I just want to decrease the number of rows in the output order to properly extract the results.
Sample
|--id-|--name--|-------date------|
| 1 | a |5-9-2015, 10:00am|
| 1 | a |5-8-2015, 10:02am|
| 1 | a |5-8-2015, 11:00am|
| 1 | b |5-8-2015, 10:00am|
| 1 | b |5-8-2015, 10:02am|
| 1 | c |5-8-2015, 10:00am|
| 2 | d |5-8-2015, 10:00am|
expected output
|--id-|--name--|
| 1 | a |
| 1 | b |
| 1 | c |
| 2 | d |
Inclusion of entries without any duplicates are fine. The important thing is to only return a single record of a unique id-name combination for a day.
Thanks in advance for any help that you can give.
You can get the combinations as:
select distinct id, name
from sample;
If you want duplicates, using group by and having:
select id, name
from sample
group by id, name
having count(*) > 1;
EDIT:
If you want this by date, then add date(date) to the group by and perhaps select clauses.
To return single id-name data per day you can use this:
select id, name
from tab
group by id, name, date(date)
The DATE() function extracts the date part of a date or date/time expression.
select id,name
from sample
group by id,name,DATE(date)
having count(*)>1;