Im still learning MySQL however I would like to know how to query multiple SELECT statements in one query.
Currently I have two queries, one that displays Order count for 12 months and another for one month. I would like to query both at the same time however receive two different results.
I have tried using UNION with my query however it only outputs into one table and its quite hard to differentiate the result with what query.
SQL:
SELECT OrderDate, OrderItems, COUNT(*) AS Total FROM tb_orders WHERE OrderDate > DATE_SUB(now(), INTERVAL 12 MONTH) GROUP BY OrderItems ORDER BY Total DESC LIMIT 10
SELECT OrderDate, OrderItems, COUNT(*) AS Total FROM tb_orders WHERE OrderDate > DATE_SUB(now(), INTERVAL 1 MONTH) GROUP BY OrderItems ORDER BY Total DESC LIMIT 10;
TIA
You can merge the 2 queries by creating an identifier on the fly whether the record is from the monthly or yearly query. Column type is a column for this purpose in below query,
SELECT z.*
FROM
(
SELECT OrderDate, OrderItems, COUNT(*) AS Total, 'YEAR' as type
FROM tb_orders
WHERE OrderDate > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY OrderItems
LIMIT 10
UNION
SELECT OrderDate, OrderItems, COUNT(*) AS Total, 'MONTH' as type
FROM tb_orders
WHERE OrderDate > DATE_SUB(now(), INTERVAL 1 MONTH)
GROUP BY OrderItems
LIMIT 10
) AS z
ORDER BY z.Total DESC;
Working Fiddle
With union, you can always add hard-coded values to help differentiate rows:
select 'Invertebrate' as AnimalPhylum, species as AnimalSpecies from invertebrates_table
union
select 'Vertebrate', species from vertebrates_table;
Related
My table currently has 21000 records, it's daily updated and almost 300 entries are inserted. Now, what I want is to have a query which will fetch the counts of elements that my table had for the previous 10 days, so it returns:
26000
21300
21000
etc
Right now, I wrote this:
"SELECT COUNT(*) from tbl_task where `task_start_time` < '2020-12-01'"
And it returns 21000 but only for 1 day. I want by query to return records according to 10 days.
However, this does it for only 1 day.
edit : database flavor is mysql and date column is date not datetime
The most efficient method may be aggregation and cumulative sums:
select date(task_start_time) as dte, count(*) as cnt_on_day,
sum(count(*)) over (order by date(task_start_time)) as running_cnt
from tbl_task
group by dte
order by dte desc
limit 10;
This returns the last 10 days in the data. You can easily adjust to more days if you like -- in fact all of them -- without much trouble.
I don't know if I'm wrong, but could you not simple add a GROUP BY - statement? Like:
"SELECT COUNT(*) from tbl_task where `task_start_time` < '2020-12-01' GROUP
BY task_start_time"
EDIT:
This should only work if task_start_time is a date, not if it is a datetime
EDIT2:
If it is a datetime you could use the date function:
SELECT COUNT(*) from tbl_task where `task_start_time` < '2020-12-01' GROUP
BY DATE(task_start_time)
You can use UNION ALL and date arithmetic.
SELECT count(*)
FROM tbl_task
WHERE task_start_time < current_date
UNION ALL
SELECT count(*)
FROM tbl_task
WHERE task_start_time < date_sub(current_date, INTERVAL 1 DAY)
...
UNION ALL
SELECT count(*)
FROM tbl_task
WHERE task_start_time < date_sub(current_date, INTERVAL 9 DAY);
Edit:
You might also join a derived table that uses FROM-less SELECTs and UNION ALL to get the days to look back and then aggregate. This might be a little easier to construct dynamically. (But it may be slower I suspect.)
SELECT count(*)
FROM (SELECT 0 x
UNION ALL
SELECT 1
...
UNION ALL
SELECT 9)
INNER JOIN tbl_task t
ON t.task_start_time < date_sub(current_date, INTERVAL x.x DAY)
GROUP BY x.x;
In MySQL version 8+ you can even use a recursive CTE to construct the table with the days.
WITH RECURSIVE x
AS
(
SELECT 0 x
UNION ALL
SELECT x + 1
FROM x
WHERE x + 1 < 10
)
SELECT count(*)
FROM x
INNER JOIN tbl_task t
ON t.task_start_time < date_sub(current_date, INTERVAL x.x DAY)
GROUP BY x.x;
I am trying to write one query in which i need to fetch/count records which are registered on same date. But the issue is that in mysql structure created_date field have "datetime" structure.
Let me give you example
If 5 people are registered on 2015-02-25 and 6 people registered on 2015-02-11. It will output as
Sno. Date. count
1) 2015-02-25 5
2) 2015-02-11 6
Here is sample of attached database rows for better understanding
http://i.stack.imgur.com/iPeLl.png
SELECT date(created_at),count(*) FROM myTable GROUP BY date(created_at)
It might be the one that you expected.
SELECT
DATE_FORMAT(created_at,"%Y-%m-%d") AS Date,
COUNT(*) AS count
FROM table_name
GROUP BY DATE_FORMAT(created_at,"%Y-%m-%d")
ORDER BY created_at DESC;
This query will count the registered people in each day. Of course the latest registration will come first.
your query should be like this:
select date(created_at) created_at, count(*) from TABLE
group by date(created_at)
Select between dates
select date(created_at) created_at, count(*) from TABLE
where date(created_at) >= '2015-02-11' and date(created_at) <= '2015-02-25'
group by date(created_at)
With between:
select date(created_at) created_at, count(*) from Mytable
where date(created_at) BETWEEN '2015-01-05' AND '2015-02-25'
group by date(created_at)
Referrence: count()
I have a query which returns the total of users who registered for each day. Problem is if a day had no one register it doesn't return any value, it just skips it. I would rather it returned zero
this is my query so far
SELECT count(*) total FROM users WHERE created_at < NOW() AND created_at >
DATE_SUB(NOW(), INTERVAL 7 DAY) AND owner_id = ? GROUP BY DAY(created_at)
ORDER BY created_at DESC
Edit
i grouped the data so i would get a count for each day- As for the date range, i wanted the total users registered for the previous seven days
A variation on the theme "build your on 7 day calendar inline":
SELECT D, count(created_at) AS total FROM
(SELECT DATE_SUB(NOW(), INTERVAL D DAY) AS D
FROM
(SELECT 0 as D
UNION SELECT 1
UNION SELECT 2
UNION SELECT 3
UNION SELECT 4
UNION SELECT 5
UNION SELECT 6
) AS D
) AS D
LEFT JOIN users ON date(created_at) = date(D)
WHERE owner_id = ? or owner_id is null
GROUP BY D
ORDER BY D DESC
I don't have your table structure at hand, so that would need adjustment probably. In the same order of idea, you will see I use NOW() as a reference date. But that's easily adjustable. Anyway that's the spirit...
See for a live demo http://sqlfiddle.com/#!2/ab5cf/11
If you had a table that held all of your days you could do a left join from there to your users table.
SELECT SUM(CASE WHEN U.Id IS NOT NULL THEN 1 ELSE 0 END)
FROM DimDate D
LEFT JOIN Users U ON CONVERT(DATE,U.Created_at) = D.DateValue
WHERE YourCriteria
GROUP BY YourGroupBy
The tricky bit is that you group by the date field in your data, which might have 'holes' in it, and thus miss records for that date.
A way to solve it is by filling a table with all dates for the past 10 and next 100 years or so, and to (outer)join that to your data. Then you will have one record for each day (or week or whatever) for sure.
I had to do this only for MS SqlServer, so how to fill a date table (or perhaps you can do it dynamically) is for someone else to answer.
A bit long winded, but I think this will work...
SELECT count(users.created_at) total FROM
(SELECT DATE_SUB(CURDATE(),INTERVAL 6 DAY) as cdate UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 5 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 4 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 3 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 2 DAY) UNION ALL
SELECT DATE_SUB(CURDATE(),INTERVAL 1 DAY) UNION ALL
SELECT CURDATE()) t1 left join users
ON date(created_at)=t1.cdate
WHERE owner_id = ? or owner_id is null
GROUP BY t1.cdate
ORDER BY t1.cdate DESC
It differs from your query slightly in that it works on dates rather than date times which your query is doing. From your description I have assumed you mean to use whole days and therefore have used dates.
I have a number of posts saved into a InnoDB table on MySQL. The table has the columns "id", "date", "user", "content". I wanted to make some statistic graphs, so I ended up using the following query to get the amount of posts per hour of yesterday:
SELECT HOUR(FROM_UNIXTIME(`date`)) AS `hour`, COUNT(date) from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) = CURDATE() - INTERVAL 1 DAY GROUP BY hour
This outputs the following data:
I can edit this query to get any day I want. But what I want now is the AVERAGE of each hour of every day, so that if on Day 1 at 00 hours I have 20 posts and on Day 2 at 00 hours I have 40, I want the output to be "30". I'd like to be able to pick date periods as well if it's possible.
Thanks in advance!
You can use a sub-query to group the data by day/hour, then take the average by hour across the sub-query.
Here's an example to give you the average count by hour for the past 7 days:
select the_hour,avg(the_count)
from
(
select date(from_unixtime(`date`)) as the_day,
hour(from_unixtime(`date`)) as the_hour,
count(*) as the_count
from fb_posts
where `date` >= unix_timestamp(current_date() - interval 7 day)
and created_on < unix_timestamp(current_date())
group by the_day,the_hour
) s
group by the_hour
Aggregate the information by date and hour, and then take the average by hour:
select hour, avg(numposts)
from (SELECT date(`date`) as day, HOUR(FROM_UNIXTIME(`date`)) AS `hour`,
count(*) as numposts
from fb_posts
WHERE DATE(FROM_UNIXTIME(`date`)) between <date1> and <date2>
GROUP BY date(`date`), hour
) d
group by hour
order by 1
By the way, I prefer including the explicit order by, since most databases do not order the results of a group by. Mysql happens to be one database that does.
SELECT
HOUR(FROM_UNIXTIME(`date`)) AS `hour`
, COUNT(`id`) \ COUNT(DISTINCT TO_DAYS(`date`)) AS avgHourlyPostCount
FROM fb_posts
WHERE `date` > '2012-01-01' -- your optional date criteria
GROUP BY hour
This gives you a count of all the posts, divided by the number of days, by hour.
I have a table with columns: NAME, CHANGE_ID, and CHANGE_DATE, where each row constitutes a single change, the columns indicated who made the change(name), when it was made(timestamp), and an id for the change(integer).
I can retrieve a list of names sorted by those that have made the most changes(in the last month) with the following query:
SELECT
NAME AS name,
COUNT(DISTINCT CHANGE_ID) AS changes
FROM
CHANGE_TABLE
WHERE
DATE(CHANGE_DATE) > DATE(now() - INTERVAL 1 MONTH)
GROUP BY
name
ORDER BY
changes DESC
And I can retrieve a list of changes made per month in the last 10 months with the following query:
SELECT
DATE_FORMAT(CHANGE_DATE, '%Y-%m') AS date,
COUNT(DISTINCT CHANGE_ID) AS change_count
FROM
CHANGE_TABLE
WHERE
CHANGE_DATE > curdate() - INTERVAL 10 MONTH
GROUP BY
date
What I want is a query that will return the combined information of these queries: I want the names of the top change-makers and how many changes they have made each month for the last 10 months. I don't particularly care how the resulting table looks as long as the data is there. I have wracked my brain, but my SQL understanding is not great enough to solve the problem. Any help would be appreciated.
Have you tried grouping on date and name, something like:
SELECT
DATE_FORMAT(CHANGE_DATE, '%Y-%m') AS date,
COUNT(DISTINCT CHANGE_ID) AS change_count,
NAME
FROM
CHANGE_TABLE, (SELECT
NAME AS name,
COUNT(DISTINCT CHANGE_ID) AS changes
FROM CHANGE_TABLE
WHERE DATE(CHANGE_DATE) > DATE(now() - INTERVAL 1 MONTH)
GROUP BY name
ORDER BY changes DESC
) subq
WHERE CHANGE_DATE > curdate() - INTERVAL 10 MONTH AND change_table.name = subq.name
GROUP BY date, name