"Every derived table must have its own alias" Mysql Error - mysql

Whats wrong with my query:
SELECT minDate, deviceType, COUNT(*)
FROM (SELECT visitorId, deviceType,
MIN(sessionDate) as minDate
FROM sessions
GROUP BY visitorId)
WHERE minDate > DATE_SUB(NOW(), INTERVAL 14 DAY)
GROUP BY minDate, deviceId
I've got this message:
Query Error: Error: ER_DERIVED_MUST_HAVE_ALIAS: Every derived table must have its own alias

The error message is clear enough. You must alias the derived table that is generated by your sub-select. So, give it an alias.
Another issue is that, in the subquery, non-aggregated column deviceType should be included in the GROUP BY clause. This change might, or might not produce the results that you do expect: if it doesn't, then you would need to provide sample data, expected results and an explanation of what you are trying to accomplish so one can help fixing the query.
SELECT minDate, deviceType, COUNT(*)
FROM (
SELECT visitorId, deviceType, MIN(sessionDate) as minDate
FROM sessions
GROUP BY visitorId, deviceType -- all non-aggregated columns in the GROUP BY clause
) t -- alias here
WHERE minDate > DATE_SUB(NOW(), INTERVAL 14 DAY)
GROUP BY minDate, deviceId

Related

Avg function not returning proper value

I expect this query to give me the avg value from daily active users up to date and grouped by month (from Oct to December). But the result is 164K aprox when it should be 128K. Why avg is not working? Avg should be SUM of values / number of current month days up to today.
SELECT sq.month_year AS 'month_year', AVG(number)
FROM
(
SELECT CONCAT(MONTHNAME(date), "-", YEAR(DATE)) AS 'month_year', count(distinct id_user) AS number
FROM table1
WHERE date between '2020-10-01' and '2020-12-31 23:59:59'
GROUP BY EXTRACT(year_month FROM date)
) sq
GROUP BY 1
Ok guys thanks for your help. The problem was that on the subquery I was pulling the info by month and not by day. So I should pull the info by day there and group by month in the outer query. This finally worked:
SELECT sq.day_month, AVG(number)
FROM (SELECT date(date) AS day_month,
count(distinct id_user) AS number
FROM table_1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY 1
) sq
GROUP BY EXTRACT(year_month FROM day_month)
Do not use single quotes for column aliases!
SELECT sq.month_year, AVG(number)
FROM (SELECT CONCAT(MONTHNAME(date), '-', YEAR(DATE)) AS month_year,
count(distinct id_user) AS number
FROM table1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY month_year
) sq
GROUP BY 1;
Note the fixes to the query:
The GROUP BY uses the same columns as the SELECT. Your query should return an error (although it works in older versions of MySQL).
The date comparisons have been simplified.
No single quotes on column aliases.
Note that the outer query is not needed. I assume it is there just to illustrate the issue you are having.

mySQL query with HAVING gives me an error. How to fix it?

When I run this query I have this error message on phpmydamin: Unknown column 'timestamp' in 'having clause'
My column name is timestamp
SELECT DISTINCT (
hash
) AS total
FROM behaviour
HAVING total =1 and date(timestamp) = curdate()
How to get the number of hash for today?
Use where. And parentheses are not appropriate for select distinct (distinct is not a function). I suspect that you intend:
SELECT COUNT(DISTINCT hash) AS total
FROM behaviour
WHERE date(timestamp) = curdate();
It is better to write the WHERE clause without using a function on the column:
SELECT COUNT(DISTINCT hash) AS total
FROM behaviour
WHERE timestamp >= curdate() AND timestamp < date_add(curdate, interval 1 day);
Although more complicated, it allows the database engine to use an index on behaviour(timestamp) (or better yet, on behaviour(timestamp, hash).
EDIT:
If you want the hash that only appear once, one method is a subquery:
select count(*)
from (select hash
from behaviour
where timestamp >= curdate() AND timestamp < date_add(curdate, interval 1 day)
group by hash
having count(*) = 1
);
To count the hash values only existing once:
select count(*)
from
(
select hash
from behavior
where date(timestamp) = curdate()
group by hash
having count(*) = 1
) dt
The inner select (derived table) will return the hash values only existing once. The outer select will count those rows.

Mysql query to count result by removing time from datetime

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()

conversion mysql to postgresql

I have a working mysql query, but I can not get it work with postgres. This is the query (I already changed date format to to_char
SELECT country as grouper, date(users.created_at) as date,
to_char(users.created_at, '%Y-%m') as date_group,
count(id) as total_count
FROM "users"
WHERE (users.created_at >= '2011-12-01')
AND (users.created_at <= '2014-02-11')
GROUP BY grouper, date_group
ORDER BY date ASC
I am getting the error:
PG::Error: ERROR: column "users.created_at" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT country as grouper, date(users.created_at) as date, t...
Thank for your help.
SELECT country as grouper, date(MIN(users.created_at)) as date,
to_char(MIN(users.created_at), '%Y-%m') as date_group,
count(id) as total_count
FROM "users"
HAVING (users.created_at >= '2011-12-01')
AND (users.created_at <= '2014-02-11')
GROUP BY grouper, date_group
ORDER BY date ASC
MySQL is not very strict. In standard conform SQL all column values have to use an aggrate function (SUM, COUNT, MAX, MIN) on non-grouping fields - when using GROUP BY.
Honestly said, I am not entirely sure about data_group in the GROUP BY; can it be dropped?
Also note that I have switched WHERE with a HAVING.
You should use every selected column in GROUP BY section.
SELECT country as grouper, to_char(created_at, '%Y-%u') as date_group, count(id) as total_count
FROM "users"
WHERE created_at >= '2013-10-01'
AND created_at <= '2014-02-11'
GROUP BY grouper, date_group
ORDER BY date_group ASC

Optimize sql query - select in select

Which is the best method for optimizing the select in select mysql query ?
This is my example:
SELECT count(distinct email)
FROM emails_stats
WHERE DATE_FORMAT(time, '%Y-%m-%d') >= '2012-12-12'
and email in (SELECT email
FROM `reminder`
WHERE DATE_FORMAT(time, '%Y-%m-%d') = '2012-12-12')
My database has over 500k entries.
SELECT count(distinct emails_stats.email)
FROM emails_stats
JOIN reminder ON emails_stats.email= reminder.email
WHERE
emails_stats.time >= CAST('2012-12-12 00:00:00' AS datetime) AND
(reminder.time BETWEEN CAST('2012-12-12 00:00:00' AS datetime) AND CAST('2012-12-12 23:59:59' AS datetime));
If you use date_format() with the table fields, mysql will need to go through each row in the table, because it needs to get the result of that date_format() function to be able to compare the value with your given string. To make it faster, create an index for the 'time' fields and use this query instead. That way mysql can determine which rows it needs just by looking up the index.
Use an exists clause instead:
SELECT count(distinct email)
FROM emails_stats
WHERE DATE_FORMAT(time, '%Y-%m-%d') >= '2012-12-12'
and exists (SELECT 1
FROM `reminder`
WHERE emails_stats.email = `reminder`.email
and DATE_FORMAT(time, '%Y-%m-%d') = '2012-12-12')
the best method is to use join here like
SELECT count(distinct emails_stats.email)
FROM emails_stats
JOIN reminder ON emails_stats.email= reminder.email
WHERE DATE_FORMAT(emails_stats.time, '%Y-%m-%d') >= '2012-12-12';