SELECT in CONCAT - mysql

I need to concatenate two columns and I use concat as I see that this function can help me.
An example for concat function is:
SELECT CONCAT(column1,'SEPARATOR',column2) FROM table
And my query is like this:
SELECT
parent_id AS keep_in_mind_parent_id,
(SELECT name FROM table WHERE id = keep_in_mind_parent_id)
FROM
table
WHERE
id = 3
How should I concatenate those columns ? I try it with CONCAT, but doesn't seem to be working.

I'm assuming the table is a tree modeled with parent links (or an "adjacency" model), something like this:
CREATE TABLE `table` (
id INTEGER UNSIGNED PRIMARY KEY,
parent_id INTEGER UNSIGNED NOT NULL,
name VARCHAR(31) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
UNIQUE (parent_id, name)
);
If you want to find the row of a given table that is the parent of another row in the same table, you can INNER JOIN a table to itself on the parent link. Then you can distinguish values in the parent and child tables by the aliases you give in the JOIN. To concatenate the names of the parent and child rows for the child whose id is 3, the join would look like this:
SELECT child.parent_id, child.id AS id,
CONCAT(parent.name, ':', child.name) AS path,
CONCAT(parent.name, ' (#', parent.id, ')') AS parent_name_id
FROM `table` AS child
INNER JOIN `table` AS parent ON child.parent_id = parent.id
WHERE child.id = 3
Then tweak the CONCAT statements to suit the exact format of what you want.

I think you might want group_concat(). Without sample data and desired results, it is hard to tell, but one likely possibility is:
SELECT parent_id AS keep_in_mind_parent_id,
(SELECT group_concat(name) FROM table WHERE id = keep_in_mind_parent_id)
FROM table
WHERE id = 3;

Related

Query within the same table with combination of 2 columns

I have this table and I need to create an SQL statement WHERE
I need to get ID which content are BOOK with value 05 and content is PAPER with value 'Y',
Result must:
id
1
3
You can group by id, filter the table on your conditions and check in the HAVING clause if both conditions are satisfied:
SELECT id
FROM tablename
WHERE (content, value) IN (('BOOK', '05'), ('PAPER', 'Y'))
GROUP BY id
HAVING COUNT(*) = 2
See the demo.
You can use subquery.
You can select in one query the id-s that meet the condition and use it as a condition
Try:
create table `content`(
id int(9) ,
content varchar (50),
value varchar (10) );
insert into content values (1,'BOOK','05'), (2,'BOOK','05'),
(3,'BOOK','05'), (4,'BOOK','07'), (5,'BOOK','07'), (1,'PAPPER','Y'),
(2,'PAPPER','N'), (3,'PAPPER','Y'), (4,'PAPPER','Y'), (5,'PAPPER','N');
select id from content where content='BOOK' and value ='05' and id in (
select distinct id from content where content='PAPPER' and value ='Y');

How to select parent rows, whose children contain a set of subvalues?

I need to select rows from images where the set of tags belonging to an image contains at least all of the tags specified in a list of strings.
CREATE TABLE images (
image_checksum varchar(56) NOT NULL,
filename varchar(56),
PRIMARY KEY (image_checksum)
);
CREATE TABLE tags (
id int NOT NULL AUTO_INCREMENT,
name varchar(64),
confidence DECIMAL(5,2),
image varchar(56) NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (image) REFERENCES images(image_checksum)
);
I have this query that returns all of the images with tags that contain ANY of the objects specified in the list. The list will be variable length depending on what comes in from the client. I have two images in my database specified. One of a dog, one of a cat. With the query I need -- I would expect to get zero results because neither image contains a dog AND a cat.
SELECT DISTINCT images.image_checksum, images.filename, tags.name, tags.confidence from images
LEFT OUTER JOIN tags ON (tags.image = images.image_checksum)
WHERE name in ('dog','cat');
Any help is appreciated!
You want window functions to count the number of matching tags. Then use that for filtering:
SELECT it.*
FROM (SELECT i.image_checksum, i.filename, t.name, tags.confidence ,
COUNT(*) OVER (PARTITION BY i.image_checksum) as num_tags
FROM images i JOIN
tags t
ON t.image = i.image_checksum
WHERE t.name in ('dog', 'cat')
) it
WHERE num_tags = 2;
you could use group_concat for this particular problem.
SELECT images.image_checksum, images.filename, tags.name,
tags.confidence
from images
LEFT OUTER JOIN tags ON (tags.image = images.image_checksum)
WHERE tags.image in (select t1.image
from tags t1
group by t1.image
having group_concat(t1.name order by t1.name asc) like '%cat,dog%');
This will return all images that have both tags, but will also return all the tags related to those images.
You would have to just make sure that the tags being searched are in alphabetical order, so that it may find them.
group_concat, by default, uses a comma as a separator for different values.
But, it can be overridden using the key word SEPARATOR
group_concat(tags.name SEPARATOR ', ')
More info can be obtained here

Before Insert MySql trigger replace new.id

I have the following scenario: I have a product_category table that manage relationships between products and categories with these columns:
id, product_id, category_id
I have another table (cat_eq) that groups some categories with another category with these columns:
id, mykey, source_cat_id, destiny_cat_id
source_cat_id column is a VARCHAR that store comma separated id's. For example: 12,25
I need to write a trigger that before inserting in product_category table checks if the new.category_id is in the set that results when making a SELECT given some mykey , for example:
if(new.category_id in
(select source_cat_id from cat_eq where clave = 'man') )
then
set new.category_id:=(select destiny_cat_id from cat_eq where clave = 'man');
When cat_eq has more than one value, let's say (12,15) the trigger works only if the id_category is in the first place of cat_eq table row.
What I want to get is the equivalent of this, wich works ok in the trigger:
if(new.category_id in (12,25) )
then
set new.category_id:=(select destiny_cat_id from cat_eq where clave = 'man');
How can I do this?
Thanks!
Think REGEXP is the easy solution here:
IF EXISTS
select 1 from cat_eq where clave = 'man' AND
source_cat_id REGEXP CONCAT('(^|,)', new.category_id, '(,|$)')
Basically, you're looking for something that either starts with the category_id and then is followed by a comma, starts with a comma is followed by the category_id then another comma, or starts with a comma, is followed by the category_id then matches the end.
A second approach might just be a LIKE clause:
select 1 from cat_eq where clave = 'man'
AND CONCAT(',',source_cat_id,',') LIKE CONCAT('%,',category_id,',%')

Filtering MySQL Select based on joined table's fields

I have two tables. Created as follows.
CREATE TABLE item (
id INT AUTO_INCREMENT,
value VARCHAR(64),
PRIMARY KEY(id)
)
CREATE TABLE tag (
name VARCHAR(32),
item_id INT /* id of element in item table */
)
I have a select statement that returns a list of elements in the 'item' table along with all the elements of the 'tag' table linking to that table. It is filtered on the contents of the item.value field.
SELECT id,value,GROUP_CONCAT(tag.name) FROM item
LEFT JOIN tag ON tag.item_id = id
WHERE value LIKE '%test%'
All good so far. Now I want to do the same but get a list of all the item table elements with a certain tag associated with it. So I replace the WHERE query with
WHERE tag.name='test'
This gives me a list of all the 'item' elements which have the tag 'test' but the grouped tag list that come along with it only includes the tag 'test'.
How do I get a list of all the elements of the table 'item' which have tag 'test' along with the full group tag list?
First, you should have a GROUP BY in your original query:
SELECT i.id, i.value, GROUP_CONCAT(tag.name)
FROM item i LEFT JOIN
tag t
ON t.item_id = i.id
WHERE i.value LIKE '%test%'
GROUP BY i.id, i.value
To get only rows that have a certain tag, add:
HAVING SUM(t.name = 'test') > 0
after the GROUP BY.

Deleting duplicate rows on MySQL (leaving at least one)

I have this table in MySQL:
id_word
lang_original (the language from the original word) VARCHAR(2)
lang_target (the language from the translated word) VARCHAR(2)
word (the word itself) VARCHAR(50)
translation (the translation) VARCHAR(50)
They should not have duplicates. Is it possible to have a sql query that finds duplicates and deletes them (leaving the first match undeleted)?
Update a duplicate would be something that has the same lang_original,lang_target and word (only those 3 fields).
It's simpler to create a new table. Previous answers are good, but I like it this way:
Create a new table with a unique key for "lang_original, lang_target, word"
CREATE TABLE new_table_can_be_renamed_later (
..your-fields...
UNIQUE unique (lang_original,lang_target,workd)
);
Then fill your new table with by selecting the old table and use IGNORE in your INSERT
INSERT IGNORE INTO new_table_can_be_renamed_later
SELECT * FROM original_table
Please consider Mysql docs for right syntax.
Could work like this:
DELETE FROM tbl
WHERE EXISTS (
SELECT *
FROM tbl t
WHERE (t.lang_original, t.lang_target, t.word)
= (tbl.lang_original, tbl.lang_target, tbl.word)
AND tbl.id_word > t.id_word
)
If #Jason is right, and MySQL does not allow to reference the delete table, here is another form that works independently:
DELETE FROM tbl
USING (
SELECT min(id_word) AS min_id, lang_original, lang_target, word
FROM tbl t
GROUP BY lang_original, lang_target, word
HAVING count(*) > 1
) x
WHERE (tbl.lang_original, tbl.lang_target, tbl.word)
= ( x.lang_original, x.lang_target, x.word)
AND tbl.id_word > x.min_id
Both variants leave the duplicate with the smallest id alive and kill the rest.
If you want to save all your translations to the word with the smallest id in a group of dupes first:
UPDATE tbl SET translation = all_trans
FROM (
SELECT min(id_word) AS min_id, group_concat(translation) AS all_trans
FROM tbl
GROUP BY lang_original, lang_target, word
HAVING count(*) > 1
) t
WHERE tbl.id_word = t.min_id
I'm not sure that you can do that.
You are probably better off doing something like
select distinct * into yournewtable from originaltable
That may work.