Each time a php script runs i want to delete old entries by id. But MySQL throws me this error:
#1111 - Invalid use of group function
This is the query:
DELETE FROM am_shoutbox WHERE MAX(msg_id)-160 > msg_id
What is the problem here? I tried around and solved it by selecting the highest id to php first and then delete with a second query, but for better performance i want to do this in one if possible.
I hope someone can figure out what is wrong with the query above.
You can't use aggregate functions in the WHERE clause. You can try something like this (using subquery that is retrieving MAX(msg_id)) :
DELETE FROM am_shoutbox
WHERE ( SELECT *
FROM ( SELECT MAX(msg_id)
FROM am_shoutbox ) m ) - 160 > msg_id
The invalid use of group function the error describes is due use of MAX(msg_id) in WHERE clause. You can use it either in a select/subselect or in the HAVING clause:
delete from am_shoutbox
where
(select (max(ams.msg_id) FROM am_shoutbox ams) - 160) > msg_id
*you may need to specify a table alias in the sub-query as above
or the more elegant and better performance way:
delete from am_shoutbox
having (max(msg_id) - 160) > msg_id
Related
I want to perform a query like to get the last record of any type in DB, at my localhost, I use Maria Db and the query is as follow:
SELECT *
FROM table_a
WHERE column_a=999
OR column_b=999
GROUP
BY `group`;
group is a column which I save type in it, for instance: marketing, blog, order, etc
This query works fine on local, but on the server I get the following error:
SQLSTATE[42000]:
Syntax error or access violation:
1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'db_name.table_a.id' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by\n
The SQL being executed was:
SELECT * FROM `table_a` WHERE (`column_a`=999) OR (`column_b`=999) GROUP BY `group`"
According to MySQL document I can use the following command to make this possible:
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
But I don't have the sufficient privilege on Db and get the following error:
#1227 - Access denied; you need (at least one of) the SUPER privilege(s) for this operation
I asked the hosting to do this for me, they replied that they don't want to do this action
I use the YII2 framework, and now I want a way to add this on the option of database_config.php of the framework or change the query to something else with the same result, and not losing performance
ONLY_FULL_GROUP_BY is a good thing, which enforces basic ANSI SQL rules. Don't change it, fix your code instead.
From there one: you want entire records, so you should not think aggregation, but filtering.
Then: in a database table, records are unordered; for your question to just make sense, you need a column that defines the ordering of rows in each group, so it unambiguous what "last" record mean. Let me assume that you have such column, called id.
Here is a typical approach at this top-1-per-group problem, using a correlated subquery for filtering:
SELECT *
FROM table_a a
WHERE
999 IN (column_a, column_b)
AND id = (
SELECT MAX(a1.id)
FROM table_a a1
WHERE 999 IN (a1.column_a, a1.column_b) AND a1.grp = a.grp
)
Alternatively, if you are running MySQL 8.0, you can use window functions:
SELECT *
FROM (
SELECT a.*,
ROW_NUMBER() OVER(PARTITION BY grp ORDER BY id DESC) rn
FROM table_a a
WHERE 999 IN (column_a, column_b)
) a
WHERE rn = 1
Side note: group is a language keyword, hence a poor choice for a column name. I renamed it to grp in the queries.
There are a few ways to "bypass" the sql_mode but be aware that the result you get might not be correct.
First you can use ANY_VALUE(). Example like this:
SELECT any_value(column_a), any_value(column_b), `group` FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
When using ANY_VALUE() function you have to write all the columns in SELECT from the table and append with ANY_VALUE() except for the column that you use in the GROUP BY.
Using MAX() or MIN() can return result but still it might not be the correct
result, especially for any row(s) that have more than 1 count:
SELECT MAX(column_a), MAX(column_b), `group`
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
Using GROUP_CONCAT will give you a view at what are the values in non-grouped columns. Compare the results with the other queries above and you can see on row(s) that returns more than one count, does the other queries returning according to what you want?
SELECT group_concat(column_a), group_concat(column_b), group_concat(`group`)
FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
I'm not sure if you can do this but you can set the sql_mode off temporarily then you should be able to run your query:
SET sql_mode=""; -- you don't need to set global privilege.
SELECT * FROM table_a
WHERE (column_a=999) OR (column_b=999) GROUP BY `group`;
Demo here.
Still, the best option is to retain the sql_mode as it is and construct the query according to the requirement.
P/S: GROUP is a reserved word in both MySQL & MariaDB. You can use it as column name but you have to always add back-ticks to define the column or else, running the query will return you an error like
Query: select * from table_a group by group
Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'group' at line 1
I want to write a query to retrieve rows who have a max version for their particular groups
For eg:
English Basic has 4 versions(test_id:1,2,4,7). But I want to retrieve the one with the max version
with this I also want to retrieve other such records of max version
I want this result
Mom Basic 20 1(version)(id:5)
Mom Intermediate 30 1(version)(id:6)
English Basic 20 5(version)(id:7)
Thanks and Let me know if you have any doubts
Here is what I've tried:
I got the SQL query:
SELECT *, MAX(`version`) FROM `test` GROUP BY `test_name`,`sub_category`,`test_type`
But I am not able to properly write it in laravel (throws syntax error)
Here are my laravel tries:
$test = Test::selectRaw('*, MAX(version) GROUP BY `test_name` ')->get();
$test = Test::selectRaw('*')->groupBy('sub_category')->toSql();
and so on
P.S. Don't worry about the format of commas or quotes as I tried all the combinations with this. Just not able to figure out what is the write code
I did not try this one. But I think you can do this. What you meant by unique is not clear.
Test::where('version', Test::max('version'))->get();
Please try this,
Mysql
select test_type,test_name,sub_category,time,max(version) as version
from table_name group by test_name,sub_categoryorder by version ;
Laravel
$result=DB::select(DB::raw("select test_type,test_name,sub_category,time,max(version) as version
from table_name group by test_name,sub_categoryorder by version"));
Check Fiddle
$maxVersion = Test::orderBy('version', 'desc')->first(); // gets the whole row
Here is the solution I found:
$test = DB::select(DB::raw("
SELECT * FROM test a
INNER JOIN (SELECT test_type, test_name,sub_category, MAX(version) AS maxversion
FROM test GROUP BY test_type,test_name,sub_category) b
ON a.test_type=b.test_type
AND a.test_name=b.test_name
AND a.sub_category=b.sub_category
AND a.version=b.maxversion"));
There is no way to easily translate this into eloquent if you could do it then please post it here. Also you need to make sql strict in your config->database file as false to run this as it has some issue with group by
I've been googling around and can't seem to find how to fix this. I'm currently using MySQL and am trying to run this
SELECT song_id FROM ‘played_songs’ WHERE id=MAX(id)
When I run this, I get the error message
1111 - Invalid use of group function
Does anyone know what I am doing wrong here? For reference, I'm trying to get the latest row's song_id in a pre-existing database. The ID increments so the latest value is the max ID in the column. When I get that column, I would like to get it's song_id in that same row.
Sorry if this is a super basic question, I've never done this before.
Thanks!
you can't use max in where clause, try this:
SELECT song_id FROM played_songs WHERE id=(SELECT max(id) FROM played_songs)
but better solution is:
SELECT song_id FROM played_songs ORDER BY id DESC LIMIT 1;
You need to use a "Having" instead of a "where". A Having is used when you are operating on a previous calculation (getting max id is a calculation mysql has to make). I would write like this.
SELECT song_id, MAX(id) as
max_id FROM ‘played_songs’
HAVING max_id=id
I have tried to set the max value for the particular column but that is not working for me. I do not know where i'm going wrong.
UPDATE `upload_video`
SET order_id ='select max(order_id)+1
FROM upload_video'
WHERE `video_id` = 22
This is my query i run the select max(order_id)+1 from upload_video query separately which is giving the result. But if i use this query in update query, the query is executing without error. But the order_id is not updating properly. please help me
Your query is almost correct in standard SQL, you only need to use brackets () instead of apostrophe ':
SET order_id = (SELECT MAX(...) ...)
but MySQL doesn't allow you to update a table while selecting from the same table, a workaround is to use a subquery that calculates the value that you need, and to join your subquery with the table you need to update:
UPDATE
upload_video JOIN (SELECT COALESCE(MAX(order_id),0)+1 max_id
FROM upload_video) s
SET
upload_video.order_id=s.max_id
WHERE
video_id=22
Please see fiddle here.
You have a typo in the statement, you used UPADTE instead of UPDATE.
One problem is, don't quote the subquery. You have used single quotes, which means the expression select max(order_id)+1... was interpreted as a text literal (a varchar). But you clearly don't want that (I guess order_id is a number). What you want instead is to evaluate the subquery. However, if you try:
UPDATE `upload_video`
SET order_id =(select max(order_id)+1
FROM upload_video)
WHERE `video_id` = 22
then MySQL doesn't allow it (I didn't know about that). Other databases such as PostgreSQL allow it. So you might need two statements:
select #id = coalesce(max(order_id), 0) + 1 FROM upload_video;
UPDATE `upload_video` SET order_id = #id WHERE `video_id` = 22;
Please note this works in MySQL but not in other databases.
Try this:
UPDATE `upload_video`
SET order_id =(select COALESCE(max(U2.order_id),0)+1
FROM upload_video U2)
WHERE `video_id` = 22
Peraphs this query goes in error because MySql doesn't want to use the same table in UPDATE and in subquery.
If your case please write two queries.
The first get the maximum value, the second does update
im making a simple admin module to query the database to show the results. Im using this query via php:
SELECT
*
FROM myTable
WHERE id in(SELECT
id_registro
FROM myOtherTable
where id_forma='".$id_club."' and fecha_visita Like '%".$hoy."%'
)
order by id DESC
The result shows, however, it takes very long like 2 minutes..Anyone can help me out?
Thanks!
Without seeing your database, it is hard to find a way to make it faster.
Maybe you can try to turn your WHERE IN to INNER JOIN. To something like this
SELECT * FROM myTable INNER JOIN myOtherTable
ON (myTable.id = myOtherTable.id_registro)
WHERE myOtherTable.id_forma = '$id_club'
AND myOtherTable.fecha_visita LIKE '%$hoy%'
ORDER BY myTable.id DESC
Noted that you should sanitize your variable before putting it SQL query or using PDO prepare statement.
Sub Queries takes always time, so its better to ignore them as much as possible.
Try to optimize your query by checking its cardinality,possible keys getting implemented by DESC or EXPLAIN , and if necessary use FORCE INDEX over possible keys.
and I guess you can modify your query as:
SELECT
*
FROM myTable
inner join id_registro
on (id = id_forma )
where
id_forma='".$id_club."' and fecha_visita Like '%".$hoy."%'
order by id DESC
LIKE in mysql may take a long time ,with or without index.
Do u have a very large DB?