I have a MySQL GROUP_CONCAT .... INSERT issue
This code works:
SELECT group_concat(tabel2.img_name separator ',')
FROM tabel2
GROUP BY tabel2.produit_id
I need to insert the result into another table and I'm stuck.
This (or any combination I could think of) doesn't work
INSERT INTO tabel1.imgname
SELECT group_concat(tabel2.img_name separator ',')
FROM tabel2
GROUP BY tabel2.produit_id
WHERE tabel1.product_id = tabel2.produit_id
What am I doing wrong?
CREATE TABLE IF NOT EXISTS `tabel1` (
`product_id` int(11) NOT NULL AUTO_INCREMENT,
`rubrique_id` int(11) NOT NULL,
`marque_id` int(11) NOT NULL,
`subfamily_id` int(11) NOT NULL,
`product_name` varchar(150) NOT NULL,
`imgname` varchar(255) DEFAULT NULL,
`product_description1` text NOT NULL,
`product_description2` text NOT NULL,
`product_order` int(11) NOT NULL,
`product_page` int(11) NOT NULL,
`price_min` float NOT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0;
INSERT INTO `tabel1` (`product_id`, `rubrique_id`, `marque_id`, `subfamily_id`, `product_name`, `imgname`, `product_description1`, `product_description2`, `product_order`, `product_page`, `price_min`)
VALUES
(33, 15, 23, 40, 'product 1', NULL, '', '', 0, 0, 0),
(34, 13, 13, 13, 'product 2', NULL, '', '', 0, 0, 0),
(35, 14, 14, 14, 'product 3', NULL, '', '', 0, 0, 0);
CREATE TABLE IF NOT EXISTS `tabel2` (
`img_id` int(11) NOT NULL AUTO_INCREMENT,
`img_name` text NOT NULL,
`article_id` int(11) DEFAULT NULL,
`produit_id` int(11) DEFAULT NULL,
`product_select` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`img_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=4018 ;
INSERT INTO `tabel2` (`img_id`, `img_name`, `article_id`, `produit_id`, `product_select`)
VALUES
(4013, 'acoacki086050.jpg', 13342, 33, NULL),
(4014, '32252il6jh2dqex.jpg', NULL, 34, NULL),
(4015, '33265ulrzmgr18w.jpg', NULL, 34, NULL),
(4016, '40334zcfk0c4n67.jpg', NULL, 35, NULL),
(4017, '40473frd4900u82.jpg', NULL, 35, NULL);
So for say tabel1.product_id = 34 I need to have tabel1.imgname = 32252il6jh2dqex.jpg,33265ulrzmgr18w.jpg
I think this is what you are trying to do:
INSERT INTO tabel1 (product_id,imgname)
SELECT tabel2.produit_id, group_concat(tabel2.img_name separator ',') as imgname
FROM tabel2
GROUP BY tabel2.produit_id
Update: Thanks for posting the schema and clarifying the requirements.
This should work for you:
UPDATE tabel1
INNER JOIN
(
SELECT tabel2.produit_id, group_concat(tabel2.img_name separator ',') AS imgname
FROM tabel2
GROUP BY tabel2.produit_id
) s ON s.produit_id = tabel1.product_id
SET tabel1.imgname = s.imgname;
What you describe is UPDATE. not INSERT:
UPDATE
tabel1 AS t1
JOIN
( SELECT produit_id
, GROUP_CONCAT(img_name SEPARATOR ',') AS grp_img_name
FROM tabel2
GROUP BY produit_id
) AS t2
ON t2.produit_id = t1.product_id
SET
t1.imgname = t2.grp_img_name ;
Random rants:
Why, why, why do you have these table1, tabel1, tabel2, tableX names? Names of any object (of tables, columns, indexes, constraints, databases) should reflect usage.
table1 says nothing.
tabel1 says nothing except that you don't spell-check your names.
It's good practice that columns used in Foreign Key constraints (and as a result for joining), have identical names (if possible). Not imgname in one table and img_name in another. Not produit_id in one and product_id in the other. It helps you, the next programmer and the guys who try to help you over SO, to not make mistakes writing ON t2.produit_id = t1.produit_id. It can also help, if you like the USING (product_id) syntax instead of the ON syntax for joins.
(update)
It seems that the different names are because the tables come from different sources/databases and it was not your choice. I would suggest you alter them to have uniform/sensible names, if you have a lot of work to do with them. If it's a one-time job, just to transfer/transform some data, don't bother.
You did not specify a value to insert
INSERT INTO tabel1.imgname
SELECT group_concat(tabel2.img_name separator ',')
FROM tabel2
GROUP BY tabel2.produit_id
WHERE tabel1.product_id = tabel2.produit_id
VALUES('','')
etc
Related
I have a MYSQL table called tbl_product
Another table called tb_opciones_productos
And a third table called tb_opciones
I need to show every item from tbl_product as follows:
How can I get one item from tbl_product and the needed rows from tb_opciones_producto to get the needed result?
EDIT:
This is my current query proposal:
SELECT tbl_product.*,
GROUP_CONCAT( (SELECT CONCAT(tb_opciones.nombre, "(+$", tb_opciones.precio, ")")
FROM tb_opciones WHERE tb_opciones.id_opcion = tb_opciones_productos.id_opcion) SEPARATOR "<br>" ) as options FROM tbl_product
INNER JOIN tb_opciones_productos ON tbl_product.id = tb_opciones_productos.producto
I've create a little sqlfiddle to test : http://sqlfiddle.com/#!9/fc3316/16
You can GROUP_CONCAT a sub-query. It may not be optimized, but it do the job.
PS: next time, can you provide a sample structure ?
Structure :
CREATE TABLE IF NOT EXISTS `products` (
`id` int(6) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `products` (`id`, `name`) VALUES
(1, 'Product Lorem'),
(2, 'Product Ipsum');
CREATE TABLE IF NOT EXISTS `products_options` (
`id_product` int(6) unsigned NOT NULL,
`id_option` int(6) unsigned NOT NULL,
PRIMARY KEY (`id_product`, `id_option`)
) DEFAULT CHARSET=utf8;
INSERT INTO `products_options` (`id_product`, `id_option`) VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 3);
CREATE TABLE IF NOT EXISTS `options` (
`id` int(6) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`value` double NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `options` (`id`, `name`, `value`) VALUES
(1, 'Option A', 42),
(2, 'Option B', 6),
(3, 'Option C', 12);
Request :
SELECT products.*,
GROUP_CONCAT(options.name, " (+$", options.value, ")" SEPARATOR "<br>")
FROM products
INNER JOIN products_options
ON products.id = products_options.id_product
INNER JOIN options
ON products_options.id_option = options.id
GROUP BY products.id
With your Structure, I think this one will work :
SELECT tbl_product.*,
GROUP_CONCAT(tb_opciones.nombre, " (+$", tb_opciones.precio, ")" SEPARATOR "<br>")
FROM tbl_product
INNER JOIN tb_opciones_productos
ON tbl_product.id = tb_opciones_productos.producto
INNER JOIN tb_opciones
ON tb_opciones_productos.opcion = tb_opciones.id
GROUP BY tbl_product.id
http://sqlfiddle.com/#!9/cfd41ef/1
I want to get every row from table person and if the clause WHERE is false I want to get null values. Is there a way to do this? Thanks in advance.
CREATE TABLE `pet` (
`owner_id` INT(11) NULL DEFAULT NULL,
`pet_type` ENUM('DOG','CAT') NULL DEFAULT NULL,
`pet_name` VARCHAR(50) NULL DEFAULT NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;
CREATE TABLE `person` (
`id` INT(11) NULL DEFAULT NULL,
`first_name` VARCHAR(50) NULL DEFAULT NULL,
`last_name` VARCHAR(50) NULL DEFAULT NULL
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;
INSERT INTO `person` (`id`, `first_name`, `last_name`) VALUES
(1, 'qwe', 'asd'),
(2, 'asd', 'fgh'),
(3, 'zxc', 'vbn');
INSERT INTO `pet` (`owner_id`, `pet_type`, `pet_name`) VALUES
(1, 'DOG', 'rex');
SELECT person.*, pet.pet_name FROM person LEFT JOIN pet ON person.id = pet.owner_id WHERE pet.pet_type = 'DOG'
Thank you Lukasz Szozda and Yogesh Sharma for your answer moving the condition to ON does what I wanted
You could move condition to ON:
SELECT person.*, pet.pet_name
FROM person
LEFT JOIN pet
ON person.id = pet.owner_id
AND pet.pet_type = 'DOG';
SQLFiddle Demo
Move to ON clause instead of going with where clause :
SELECT person.*, pet.pet_name
FROM person LEFT JOIN
pet
ON person.id = pet.owner_id and pet.pet_type = 'DOG';
You where clause turns into inner join which is the problem.
i have got the below query which references couple of views 'goldedRunQueries' and 'currentGoldMarkings'. My issue seems to be from the view that is referred in the subquery - currentGoldMarkings. While execution, MySQL first materializes this subquery and then implements the where clauses of 'queryCode' and 'runId', which therefore results in execution time of more than hour as the view refers tables that has got millions of rows of data. My question is how do I enforce those two where conditions on the subquery before it materializes.
SELECT goldedRunQueries.queryCode, goldedRunQueries.runId
FROM goldedRunQueries
LEFT OUTER JOIN
( SELECT measuredRunId, queryCode, COUNT(resultId) as c
FROM currentGoldMarkings
GROUP BY measuredRunId, queryCode
) AS accuracy ON accuracy.measuredRunId = goldedRunQueries.runId
AND accuracy.queryCode = goldedRunQueries.queryCode
WHERE goldedRunQueries.queryCode IN ('CH001', 'CH002', 'CH003')
and goldedRunQueries.runid = 5000
ORDER BY goldedRunQueries.runId DESC, goldedRunQueries.queryCode;
Here are the two views. Both of these also get used in a standalone mode and so integrating any clauses into them is not possible.
CREATE VIEW currentGoldMarkings
AS
SELECT result.resultId, result.runId AS measuredRunId, result.documentId,
result.queryCode, result.queryValue AS measuredValue,
gold.queryValue AS goldValue,
CASE result.queryValue WHEN gold.queryValue THEN 1 ELSE 0 END AS correct
FROM results AS result
INNER JOIN gold ON gold.documentId = result.documentId
AND gold.queryCode = result.queryCode
WHERE gold.isCurrent = 1
CREATE VIEW goldedRunQueries
AS
SELECT runId, queryCode
FROM runQueries
WHERE EXISTS
( SELECT 1 AS Expr1
FROM runs
WHERE (runId = runQueries.runId)
AND (isManual = 0)
)
AND EXISTS
( SELECT 1 AS Expr1
FROM results
WHERE (runId = runQueries.runId)
AND (queryCode = runQueries.queryCode)
AND EXISTS
( SELECT 1 AS Expr1
FROM gold
WHERE (documentId = results.documentId)
AND (queryCode = results.queryCode)
)
)
Note: The above query reflects only a part of my actual query. There are 3 other left outer joins which are similar in nature to the above subquery which makes the problem far more worse.
EDIT: As suggested, here is the structure and some sample data for the tables
CREATE TABLE `results`(
`resultId` int auto_increment NOT NULL,
`runId` int NOT NULL,
`documentId` int NOT NULL,
`queryCode` char(5) NOT NULL,
`queryValue` char(1) NOT NULL,
`comment` varchar(255) NULL,
CONSTRAINT `PK_results` PRIMARY KEY
(
`resultId`
)
);
insert into results values (100, 242300, 'AC001', 'I', NULL)
insert into results values (100, 242300, 'AC001', 'S', NULL)
insert into results values (150, 242301, 'AC005', 'I', 'abc')
insert into results values (100, 242300, 'AC001', 'I', NULL)
insert into results values (109, 242301, 'PQ001', 'S', 'zzz')
insert into results values (400, 242400, 'DD006', 'I', NULL)
CREATE TABLE `gold`(
`goldId` int auto_increment NOT NULL,
`runDate` datetime NOT NULL,
`documentId` int NOT NULL,
`queryCode` char(5) NOT NULL,
`queryValue` char(1) NOT NULL,
`comment` varchar(255) NULL,
`isCurrent` tinyint(1) NOT NULL DEFAULT 0,
CONSTRAINT `PK_gold` PRIMARY KEY
(
`goldId`
)
);
insert into gold values ('2015-02-20 00:00:00', 138904, 'CH001', 'N', NULL, 1)
insert into gold values ('2015-05-20 00:00:00', 138904, 'CH001', 'N', 'aaa', 1)
insert into gold values ('2016-02-20 00:00:00', 138905, 'CH002', 'N', NULL, 0)
insert into gold values ('2015-12-12 00:00:00', 138804, 'CH001', 'N', 'zzzz', 1)
CREATE TABLE `runQueries`(
`runId` int NOT NULL,
`queryCode` char(5) NOT NULL,
CONSTRAINT `PK_runQueries` PRIMARY KEY
(
`runId`,
`queryCode`
)
);
insert into runQueries values (100, 'AC001')
insert into runQueries values (109, 'PQ001')
insert into runQueries values (400, 'DD006')
CREATE TABLE `runs`(
`runId` int auto_increment NOT NULL,
`runName` varchar(63) NOT NULL,
`isManual` tinyint(1) NOT NULL,
`runDate` datetime NOT NULL,
`comment` varchar(1023) NULL,
`folderName` varchar(63) NULL,
`documentSetId` int NOT NULL,
`pipelineVersion` varchar(50) NULL,
`isArchived` tinyint(1) NOT NULL DEFAULT 0,
`pipeline` varchar(50) NULL,
CONSTRAINT `PK_runs` PRIMARY KEY
(
`runId`
)
);
insert into runs values ('test1', 0, '2015-08-04 06:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL)
insert into runs values ('test2', 1, '2015-12-04 12:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL)
insert into runs values ('test3', 1, '2015-06-24 10:56:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL)
insert into runs values ('test4', 1, '2016-05-04 11:30:46.000000', 'zzzz', '2015-08-04_103046', 2, '2015-08-03', 0, NULL)
First, let's try to improve the performance via indexes:
results: INDEX(runId, queryCode) -- in either order
gold: INDEX(documentId, query_code, isCurrent) -- in that order
After that, update the CREATE TABLEs in the question and add the output of:
EXPLAIN EXTENDED SELECT ...;
SHOW WARNINGS;
What version are you running? You effectively have FROM ( SELECT ... ) JOIN ( SELECT ... ). Before 5.6, neither subquery had an index; with 5.6, an index is generated on the fly.
It is a shame that the query is built that way, since you know which one to use: and goldedRunQueries.runid = 5000.
Bottom Line: add the indexes; upgrade to 5.6 or 5.7; if that is not enough, then rethink the use of VIEWs.
I'm having three tables: articles, tags and articles_tags. As you can imagine, each article can have multiple tags and each tag can be assigned to multiple articles. I have so-called main article (represented by unique URL) and would like to get related articles of it, based on shared tags between them like: if main article and article 2 has one tag in common, show both articles (and ideally, it would not show/include in the results the main article). Unique URL of main article is passed in SQL query.
The expected result is beyond my reach, so any help would be appreciated.
SQLFiddle
Copied code, if site above goes offline:
Databases and content:
CREATE TABLE `articles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`status` tinyint(4) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `articles_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`article_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `articles` (`url`, `title`, `status`) VALUES
('test-article-1', 'Test Article #1', 1),
('test-article-2', 'Test Article #2', 1),
('test-article-3', 'Test Article #3', 0),
('test-article-4', 'Test Article #4', 0),
('test-article-5', 'Test Article #5', 1);
INSERT INTO `tags` (`tag`, `url`) VALUES
('Test', 'test'),
('City', 'city'),
('Nature', 'nature');
INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 2),
(3, 1),
(3, 2),
(4, 2),
(5, 1);
Latest (not working properly) SQL query:
SELECT
tags.tag,
articles.url,
articles.title
FROM articles
LEFT JOIN articles_tags ON articles_tags.article_id=articles.id
LEFT JOIN tags ON articles_tags.tag_id=tags.id
WHERE (articles.url='test-article-1'
OR tags.id IN (articles_tags.tag_id))
AND articles.status=1
GROUP BY articles.id
Result:
As you can see on SQLFiddle, it shows articles 1, 2 and 5, but in my mind it should show only 1 and 5
Expected Result: Articles 1 and 5, ideally only 5 (excluding article 1 because it's the main one).
I am not quite sure I understand why you didn't expect article 2 in your results, as it and article 1 both have tag 2. This below should still return article 2, so it may not be what you want, but it is the most straight forward "similarly tagged ranking" query I can think of:
SELECT b.*, COUNT(1) AS tagMatches
FROM articles AS a
INNER JOIN articles_tags AS aTags ON a.id=aTags.article_id
INNER JOIN articles_tags AS bTags
ON aTags.article_id<>bTags.article_id
AND aTags.tag_id = bTags.tag_id
INNER JOIN articles AS b ON bTags.article_id
WHERE a.url = ?
GROUP BY b.url
ORDER BY tagMatches DESC, b.title
;
Edit: This assumes articles cannot have the same tag more than once. If this is not the case, it will skew the rankings (but that might be favorable if the duplicated tags should have more weight).
Edit2: It is also worth noting, that * probably should not be used for final results; I just used it here for simplicity.
Your OR condition OR tags.id IN (articles_tags.tag_id)) fires on these rows:
INSERT INTO `articles_tags` (`article_id`, `tag_id`) VALUES
(1, 1),
...
(3, 1),
...,
(5, 1);
so, for me the result looks fine
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