Before Insert MySql trigger replace new.id - mysql

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,',%')

Related

Searching for data in SQL

Please take a look at the following table:
I am building a search engine which returns card_id values, based on search of category_id and value_id values.
To better explain the search mechanism, imagine that we are trying to find a car (card_id) by supplying information what part (value_id) the car should has in every category (category_id).
In example, we may want to find a car (card_id), where category "Fuel Type" (category_id) has a value "Diesel" (value_id), and category "Gearbox" (category_id) has a value "Manual" (value_id).
My problem is that my knowledge is not sufficient to build a query, which will returns card_ids which contains more than one pair of category_id and value_id.
For example, if I want to search a car with diesel engine, I could build a query like this:
SELECT card_id FROM cars WHERE category_id=1 AND value_id=2
where category_id = 1 is a category "Fuel Type" and value_id = 2 is "Diesel".
My question is, how can I build a query, which will look for more category-value pairs? For example, I want to look for diesel cars with manual gearbox.
Any help will be very appreciated. Thank you in advance.
You can do this using aggregation and a having clause:
SELECT card_id
FROM cars
GROUP BY card_id
HAVING SUM(category_id = 1 AND value_id = 2) > 0 AND
SUM(category_id = 3 and value_id = 43) > 0;
Each condition in the having clause counts the number of rows that match a given condition. You can add as many conditions as you like. The first, for instance, says that there is at least one row where the category is 1 and the value is 2.
SQL Fiddle
Another approach is to create a user defined function that takes a table of attribute/value pairs and returns a table of matching cars. This has the advantage of allowing an arbitrary number of attribute/value pairs without resorting to dynamic SQL.
--Declare a "sample" table for proof of concept, replace this with your real data table
DECLARE #T TABLE(PID int, Attr Int, Val int)
--Populate the data table
INSERT INTO #T(PID , Attr , Val) VALUES (1,1,1), (1,3,5),(1,7,9),(2,1,2),(2,3,5),(2,7,9),(3,1,1),(3,3,5), (3,7,9)
--Declare this as a User Defined Table Type, the function would take this as an input
DECLARE #C TABLE(Attr Int, Val int)
--This would be populated by the code that calls the function
INSERT INTO #C (Attr , Val) VALUES (1,1),(7,9)
--The function (or stored procedure) body begins here
--Get a list of IDs for which there is not a requested attribute that doesn't have a matching value for that ID
SELECT DISTINCT PID
FROM #T as T
WHERE NOT EXISTS (SELECT C.ATTR FROM #C as C
WHERE NOT EXISTS (SELECT * FROM #T as I
WHERE I.Attr = C.Attr and I.Val = C.Val and I.PID = T.PID ))

MySQL INSERT INTO table 1 SELECT table 2 with different column name

I have a table (pdt_1) in database (db_1) and another table (pdt_2) in another database (db_2).
I met pdt_1 and pdt_2 to find pdt_1 products not present and published in pdt_2.
functional code :
SELECT * FROM db_1.pdt_1 AS lm
WHERE lm.product_sku
NOT IN (SELECT DISTINCT product_cip7 FROM db_2.pdt_2)
AND lm.product_publish=‘Y'
finally, I need to insert the result of this query in pdt_2.
However, the structure of pdt_1 and pdt_2 are different.
Example:
- columns's names
- columns's numbers
I also need an auto_increment id for pdt_1 products inserted into pdt_2.
I need help.
NB : sorry for my poor english :(
If you want a new table with just the id and product_sku, try:
INSERT INTO new_table # with id and product_sku from first table
SELECT pdt_1.id,
pdt_1.product_sku
FROM db_1.pdt_1
LEFT JOIN db_2.pdt_2
ON pdt_1.product_sku = pdt_2.product_cip7
WHERE pdt_2.product_cip7 IS NULL
AND pdt_1.product_publish = 'Y'

Get a list of ids not present in a table

I have a list of ids, and I want to query a mysql table for ids not present in the table.
e.g.
list_of_ids = [1,2,4]
mysql table
id
1
3
5
6
..
Query should return [2,4] because those are the ids not in the table
since we cant view ur code i can only work on asumption
Try this anyway
SELECT id FROM list_of_ids
WHERE id NOT IN (SELECT id
FROM table)
I hope this helps
There is a horrible text-based hack:
SELECT
substr(result,2,length(result)-2) AS notmatched
FROM (
SELECT
#set:=replace(#set,concat(',',id,','),',') AS result
FROM (
select #set:=concat(',',
'1,2,4' -- your list here
,',')
) AS setinit,
tablename --Your tablename here
) AS innerview
ORDER BY LENGTH(result)
LIMIT 1;
If you represent your ids as a derived table, then you can do this directly in SQL:
select list.val
from (select 1 as val union all
select 2 union all
select 4
) list left outer join
t
on t.id = list.val
where t.id is null;
SQL doesn't really have a "list" type, so your question is ambiguous. If you mean a comma separated string, then a text hack might work. If you mean a table, then something like this might work. If you are constructing the SQL statement, I would advise you to go down this route, because it should be more efficient.

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.

sql query for deleting rows with NOT IN using 2 columns

I have a table with a composite key composed of 2 columns, say Name and ID. I have some service that gets me the keys (name, id combination) of the rows to keep, the rest i need to delete. If it was with only 1 row , I could use
delete from table_name where name not in (list_of_valid_names)
but how do I make the query so that I can say something like
name not in (valid_names) and id not in(valid_ids)
// this wont work since they separately dont identity a unique record or will it?
Use mysql's special "multiple value" in syntax:
delete from table_name
where (name, id) not in (select name, id from some_table where some_condition);
If your list is a literal list, you can still use this approach:
delete from table_name
where (name, id) not in (select 'john', 1 union select 'sally', 2);
Actually, no I retract my comment about needing special juice or being stuck with (AND OR'ing all your options).
Since you have a list of values of what you want to retain, dump that into a temporary table. Then do a delete against the base table for what does not exist in the temporary table (left outer join). I suck at mysql syntax or I'd cobble together your query. Psuedocode is approximate
DELETE
B
FROM
BASE B
LEFT OUTER JOIN
#RETAIN R
ON R.key1 = B.key1
AND R.key2 = B.key
WHERE
R.key1 IS NULL
The NOT EXISTS version:
DELETE
b
FROM
BaseTable b
WHERE
NOT EXISTS
( SELECT
*
FROM
RetainTable r
WHERE
(r.key1, r.key2) = (b.key1, b.key2)
)