Invalid use of group function - MySQL using COALESCE - mysql

I want a database table with links that are used to generate the navigation on a website. For instance, the text 'Home' will link to 'http://example.com/home' and the text 'Twitter' will link to the Twitter URL, etc. I also wanted to be able to change the order in which the links are presented, hence the order column. I also want to be able to edit the links, that's why I'm using auto_incremented id's.
Now I want order to be unique, so my plan was to get the max of order and just add one. This is the query I'm using, but it will return: Invalid use of group function
INSERT INTO
`links`
(`id`, `order`, `text`, `html_text`, `link`, `html_link`)
VALUES
(NULL, COALESCE((MAX(`order`) + 1), 1), 'text', 'text (html)', 'url', 'url (html)');
My table is like this:
CREATE TABLE IF NOT EXISTS `links` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order` int(11) NOT NULL,
`text` varchar(31) NOT NULL,
`html_text` varchar(63) NOT NULL,
`link` varchar(127) NOT NULL,
`html_link` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `order` (`order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
How do I get a valid query doing just what I want?
Thanks in advance!

If you want to do it in one shot, you'll have to do an INSERT ... SELECT combination to get the value from the database and insert based on it;
INSERT INTO
`links`
(`id`, `order`, `text`, `html_text`, `link`, `html_link`)
SELECT
NULL, COALESCE((MAX(`order`) + 1), 1), 'text', 'text (html)', 'url', 'url (html)'
FROM `links`;
An SQLfiddle to test with.

Related

Order between multiple GROUP_CONCAT columns

I can't seem to find any information about GROUP_CONCAT function default behavior, maily when i use multiple of those, will the returned values have the same order in between them?
For this example table & data:
CREATE TABLE `test` (
`id` int(11) NOT NULL,
`parentId` int(11) NOT NULL,
`weight` int(11) NOT NULL,
`color` varchar(7) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `test` (`id`, `parentId`, `weight`, `color`) VALUES
(1, 1, 500, '#aa11dd'),
(2, 1, 770, '#ffffff'),
(3, 2, 100, '#ff00ff'),
(4, 2, 123, '#556677');
If I do this select:
SELECT `parentId`,
GROUP_CONCAT(`weight`),
GROUP_CONCAT(`color`),
GROUP_CONCAT(`id`)
FROM `test`
GROUP BY `parentId`
It returns:
parentId GROUP_CONCAT(weight) GROUP_CONCAT(color) GROUP_CONCAT(id)
1 500,770 #aa11dd,#ffffff 1,2
2 79798,123 #ff00ff,#556677 3,4
Is it ever possible that for example in the first line values 500,770 will flip into 770,500 but the rest of columns remain the same (#aa11dd,#ffffff; 1,2)? I don't really care about the overall order (DESC / ASC), all i want to know is, if each column has always the same order as the others?
In the absence of the ORDER BY clause inside the GROUP_CONCAT() function the engine is free to assemble the value in any order, and this order is not stable over time. Each GROUP_CONCAT() function may have a different ordering as well.
To ensure a stable ordering use ORDER BY inside the GROUP_CONCAT() function.
For example;
SELECT
`parentId`,
GROUP_CONCAT(`weight` order by `id`),
GROUP_CONCAT(`color` order by `id`),
GROUP_CONCAT(`id` order by `id`)
FROM `test`
GROUP BY `parentId`
This example orders all values by id to ensure a stable, known order, and also to ensure that each column has always the same order as the others.
According to docs, you can specify the exact order:
GROUP_CONCAT(DISTINCT `weight` ORDER BY `weight` ASC SEPARATOR ', ')
The default order is unknown

How to get auto-increment PK on a multi-row insert in MySql

I need to get back a list of "affected" ids when inserting multiple rows at once. Some rows might already be there, resulting in an update instead.
DDL:
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`email` varchar(100) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`update_time` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
UNIQUE KEY `email` (`email`)
)
Query:
INSERT INTO users (id, email, is_active)
VALUES (NULL, "joe#mail.org", true),
(NULL, "jack#mail.org", false),
(NULL, "dave#mail.org", true)
ON DUPLICATE KEY UPDATE
is_active = VALUES(is_active)
There is a UNIQUE constraint on email.
From what I gathered, LAST_INSERT_ID() would only give me first generated id of the batch. But I wouldn't know how many inserts/updates really took place.
The only way I could come up with is to follow with a second SELECT statement:
SELECT id
FROM users
WHERE email IN ("joe#mail.org", "jack#mail.org", "dave#mail.org")
Is there a better way?

SQL group by using distinct column

I am currently collecting lap times in a sql database and are having some difficulties with extracting the drivers with fastest laptimes!
The structure looks like the following!
CREATE TABLE IF NOT EXISTS `leaderboard` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`driver` varchar(50) NOT NULL,
`car` varchar(50) NOT NULL,
`best` double NOT NULL,
`guid` bigint(255) NOT NULL,
`server_name` varchar(255) NOT NULL,
`track` varchar(55) NOT NULL,
PRIMARY KEY (`id`),
KEY `driver` (`driver`),
KEY `server_name` (`server_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1213 ;
Data example
INSERT INTO `leaderboard` (`id`, `driver`, `car`, `best`, `guid`, `server_name`, `track`) VALUES
(1, 'dave.38', 'bmw_m3_e30', 88.379, 76561198084629688, 'A++%21+A++%21+------+Saturdaynightracing.tk+-+%5BRACE-SERVER%5D+-+%5BMagione%5D+%23SNR', 'magione'),
(2, 'Gabriel Porfírio', 'bmw_m3_e30', 87.318, 76561197987062834, 'A++%21+A++%21+------+Saturdaynightracing.tk+-+%5BRACE-SERVER%5D+-+%5BMagione%5D+%23SNR', 'magione'),
(3, 'xX_VEGA_Xx', 'bmw_m3_e30', 88.23, 76561198182074333, 'A++%21+A++%21+------+Saturdaynightracing.tk+-+%5BRACE-SERVER%5D+-+%5BMagione%5D+%23SNR', 'magione'),
(4, 'dave.38', 'bmw_m3_e30', 88.379, 76561198084629688, 'A++%21+A++%21+------+Saturdaynightracing.tk+-+%5BRACE-SERVER%5D+-+%5BMagione%5D+%23SNR', 'magione'),
(5, 'Gabriel Porfírio', 'bmw_m3_e30', 87.318, 76561197987062834, 'A++%21+A++%21+------+Saturdaynightracing.tk+-+%5BRACE-SERVER%5D+-+%5BMagione%5D+%23SNR', 'magione');
Now i am trying to sort out the drivers with best time using column best using the following SQL but it appears as if some times are discarded, the combination of sort and order does not work.
SELECT DISTINCT guid, car, best, driver FROM `leaderboard` WHERE `server_name` like '%%' AND `track` = 'magione' GROUP BY(driver) ORDER BY `best` * 1 LIMIT 10
Please help this is driving me mad!
Some fields in your data are not very clear, so I made such assumptions:
guid means driver's guid (because it is the same for the same driver in your data).
car is the same for the same driver.
With these assumptions you can use simple GROUP BY to get the results that you need:
SELECT driver, car, MIN(best) as best_time, guid
FROM leaderboard
WHERE `server_name` like '%%' AND `track` = 'magione'
GROUP BY driver, car, guid
ORDER BY MIN(best)

Get distinct RegEx Matches on mySQL

I need some help from the RegEx and SQL nerds. ^^
I've a comment field in a table, which content looks like this:
What I need is a DISTINCT list of all user names - eg.
b.willis
p.fox
g.clooney
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`comment` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
INSERT INTO `comments` (`id`, `comment`) VALUES
(1, 'test [name](p.fox)[/name]'),
(2, 'another test [name](p.fox)[/name]'),
(3, 'lalala [name](b.willis)[/name]'),
(4, 'lulu [name](g.clooney)[/name]');
Thx!
One way to approach this is using substring_index(). Assuming each comment has this structure and only has one name:
select distinct substring_index(substring_index(comment, '[name](', 2), ')[/name]', 1) as name
from comments
See the thread MySQL - Return matching pattern in REGEXP query
Also check How to do a regular expression replace in MySQL? and the referenced UDF implementation of RegExp. Take a look on the implementation of the UDF REGEXP_SUBSTR

Get all items from table while joining with a second table in a single query

I got two tables:
CREATE TABLE IF NOT EXISTS `groups2rights` (
`groups2rights_group_id` int(11) NOT NULL default '0',
`groups2rights_right` int(11) NOT NULL default '0',
PRIMARY KEY (`groups2rights_group_id`,`groups2rights_right`),
KEY `groups2rights_right` (`groups2rights_right`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `groups2rights` (`groups2rights_group_id`, `groups2rights_right`) VALUES (1, 35);
CREATE TABLE IF NOT EXISTS `rights` (
`right` int(11) NOT NULL auto_increment,
`right_name` varchar(255) default NULL,
`description` text NOT NULL,
`category` int(11) NOT NULL default '0',
PRIMARY KEY (`right`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=36 ;
INSERT INTO `rights` (`right`, `right_name`, `description`, `category`) VALUES
(33, 'admin_right_group_add', '', 100),
(34, 'admin_right_group_edit', '', 0),
(35, 'admin_right_group_delete', '', 0);
ALTER TABLE `groups2rights` ADD CONSTRAINT `groups2rights_ibfk_4` FOREIGN KEY (`groups2rights_right`) REFERENCES `rights` (`right`) ON DELETE CASCADE;
Now I tried to select all available Rights and also get if the group has it assigned, but somehow I'm missing some of the rights. Query:
SELECT r.*,g2r.groups2rights_group_id
FROM rights AS r
LEFT JOIN groups2rights AS g2r ON (g2r.groups2rights_right=r.right)
WHERE g2r.groups2rights_group_id=<<ID>> OR g2r.groups2rights_group_id IS NULL
ORDER BY r.category,r.right_name ASC
Any ideas?
Edit:
Updated the Code.
Expected Result be 3 Rows with 2 of them Havin a Null field and one having a value set.
If you do
SELECT r.*,g2r.group_id
FROM rights AS r
LEFT JOIN groups2rights AS g2r ON (g2r.right=r.right)
WHERE g2r.group_id=<<#id>> OR g2r.group_id IS NULL
ORDER BY r.category,r.right_name ASC
You will not gets rows where g2r.group_id <> null and also g2r.group_id <> <<#id>>
If you want to get all rows in rights and some of the rows in groups2rights you should do:
SELECT r.*,g2r.group_id
FROM rights AS r
LEFT JOIN (SELECT * FROM groups2rights WHERE group_id=<<#id>>) AS g2r
ON (g2r.right=r.right)
ORDER BY r.category,r.right_name ASC
This should work.
So you want to return all results found in the right table? In this case you should be using a RIGHT JOIN. This will return all results from the right table regardless of it matching the left table.
http://www.w3schools.com/sql/sql_join_right.asp