Insert multiple rows without duplicating them - MySQL - mysql

I'm trying to execute this query nut it seems that it returns errors:
INSERT INTO `categories` (`name`,`path`) VALUES ('TEST 1' , 'test-1'),('TEST 2' , 'test-2'),('TEST 3' , 'test-3')
WHERE (`name`,`path`) NOT IN (SELECT `name`,`path` FROM `categories`);
Any help with this? Much appreciated.

The logic you are attempted is implemented using syntax like this:
INSERT INTO `categories` (`name`,`path`)
SELECT name, path
FROM (SELECT 'TEST 1' as name, 'test-1' as path UNION ALL
SELECT 'TEST 2', 'test-2' UNION ALL
SELECT 'TEST 3' , 'test-3'
) t
WHERE NOT EXISTS (SELECT 1
FROM categories c
WHERE c.name = t.name and c.path = t.path
);
However, you should be doing the checking in the database with a unique index. So the better solution is to do the insert and just have:
create unique index idx_categories_name_path on categories(name, path)
With an insert like:
INSERT INTO `categories` (`name`,`path`)
SELECT name, path
FROM (SELECT 'TEST 1' as name, 'test-1' as path UNION ALL
SELECT 'TEST 2', 'test-2' UNION ALL
SELECT 'TEST 3' , 'test-3'
) t
ON DUPLICATE KEY UPDATE name = VALUES(name);

Related

How to replace multiple values in a single column with SQL?

I have a column with complex user id. I want to replace the text within my select query.
This creates a new column as updated_by for every single value. I want them to be replaced in a single column. How can I achieve this?
select replace(updated_by, '5eaf5d368141560012161636', 'A'),
replace(updated_by, '5e79d03e9abae00012ffdbb3', 'B'),
replace(updated_by, '5e7b501e9abae00012ffdbd6', 'C'),
replace(updated_by, '5e7b5b199abae00012ffdbde', 'D'),
replace(updated_by, '5e7c817c9ca5540012ea6cba', 'E'),
updated_by
from my_table
GROUP BY updated_by;
In Postgres I would use a VALUES expression to form a derived table:
To just select:
SELECT *
FROM my_table m
JOIN (
VALUES
('5eaf5d368141560012161636', 'A')
, ('5e79d03e9abae00012ffdbb3', 'B')
, ('5e7b501e9abae00012ffdbd6', 'C')
, ('5e7b5b199abae00012ffdbde', 'D')
, ('5e7c817c9ca5540012ea6cba', 'E')
) u(updated_by, new_value) USING (updated_by);
Or LEFT JOIN to include rows without replacement.
You may need explicit type casts with non-default data types. See:
Casting NULL type when updating multiple rows
For repeated use, create a persisted translation table.
CREATE TABLE updated_by_translation (updated_by text PRIMARY KEY, new_value text);
INSERT INTO my_table
VALUES
('5eaf5d368141560012161636', 'A')
, ('5e79d03e9abae00012ffdbb3', 'B')
, ('5e7b501e9abae00012ffdbd6', 'C')
, ('5e7b5b199abae00012ffdbde', 'D')
, ('5e7c817c9ca5540012ea6cba', 'E')
;
Data types and constraints according to your actual use case.
SELECT *
FROM my_table m
LEFT JOIN updated_by_translation u USING (updated_by);
MySQL recently added a VALUES statement, too. The manual:
VALUES is a DML statement introduced in MySQL 8.0.19
But it requires the keyword ROW for every row. So:
...
VALUES
ROW('5eaf5d368141560012161636', 'A')
, ROW('5e79d03e9abae00012ffdbb3', 'B')
, ROW('5e7b501e9abae00012ffdbd6', 'C')
, ROW('5e7b5b199abae00012ffdbde', 'D')
, ROW('5e7c817c9ca5540012ea6cba', 'E')
...
Use case:
select case updated_by
when '5eaf5d368141560012161636' then 'A'
when '5e79d03e9abae00012ffdbb3' then 'B'
when '5e7b501e9abae00012ffdbd6' then 'C'
when '5e7b5b199abae00012ffdbde' then 'D'
when '5e7c817c9ca5540012ea6cba' then 'E'
end as updated_by
from my_table
This has to be nested liek this
SELECT
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(updated_by,
'5e7c817c9ca5540012ea6cba',
'E'),
'5e7b5b199abae00012ffdbde',
'D'),
'5e7b501e9abae00012ffdbd6',
'C'),
'5e79d03e9abae00012ffdbb3',
'B'),
'5eaf5d368141560012161636',
'A'),
updated_by
FROM
my_table
GROUP BY updated_by
This will replace all occurring, patterns, if they are not foung nothing happens
You can use a recursive CTE if you need to handle multiple values within a single row:
with replacements as (
select '5eaf5d368141560012161636' as oldval, 'A' as newval union all
select '5e79d03e9abae00012ffdbb3' as oldval, 'B' union all
select '5e7b501e9abae00012ffdbd6' as oldval, 'C' union all
select '5e7b5b199abae00012ffdbde' as oldval, 'D' union all
select '5e7c817c9ca5540012ea6cba' as oldval, 'E'
),
r as (
select r.*, row_number() over (order by oldval) as seqnum
from replacements r
),
recursive cte (
select r.seqnum, replace(t.updated_by, r.oldval, r.newval) as updated_by
from my_table t join
r
on r.seqnum = 1
union all
select r.seqnum, replace(cte.updated_by, r.oldval, r.newval) as updated_by
from cte t join
r
on r.seqnum = cte.seqnum + 1
)
select cte.*
from cte
where seqnum = (select count(*) from replacements);

Error Code: 1060. Duplicate column name

I've been receiving Error Code: 1060. :
Duplicate column name 'NULL'
Duplicate column name '2016-08-04 01:25:06'
Duplicate column name 'john'
However, I need to insert some field with the same value, but SQL is denying and showing the above error. The error is probably sql can't select the same column name, in that case is there other way of writing the code? Below is my current code
INSERT INTO test.testTable SELECT *
FROM (SELECT NULL, 'hello', 'john', '2016-08-04 01:25:06', 'john'
, '2016-08-04 01:25:06', NULL, NULL) AS tmp
WHERE NOT EXISTS (SELECT * FROM test.testTable WHERE message= 'hello' AND created_by = 'john') LIMIT 1
My Column:
(id, message, created_by, created_date, updated_by, updated_date, deleted_by, deleted_date)
Please assist, thanks.
Your duplicate column names are coming from your subquery. You select null, john, and 2016-08-04 01:25:06 multiple times. Provide the columns you are selecting with names/aliases:
INSERT INTO test.testTable
SELECT *
FROM (SELECT NULL as col1, 'hello' as col2,
'john' as col3, '2016-08-04 01:25:06' as col4,
'john' as col5, '2016-08-04 01:25:06' as col6,
NULL as col7, NULL as col8) AS tmp
WHERE NOT EXISTS (SELECT *
FROM test.testTable
WHERE message= 'hello' AND created_by = 'john')
LIMIT 1
Not sure limit 1 is useful here, you are only selecting a single row to potentially insert.
You are using a subquery. Because you don't give the columns aliases, MySQL has to choose aliases for you -- and it chooses the formulas used for the definition.
You can write the query without the subquery:
INSERT INTO test.testTable( . . .)
SELECT NULL, 'hello', 'john', '2016-08-04 01:25:06', 'john',
'2016-08-04 01:25:06', NULL, NULL
FROM dual
WHERE NOT EXISTS (SELECT 1
FROM test.testTable tt
WHERE tt.message = 'hello' AND tt.created_by = 'john'
);
If you do use a subquery in the SELECT, then use correlation clauses in the WHERE subquery:
INSERT INTO test.testTable( . . .)
SELECT *
FROM (SELECT NULL as col1, 'hello' as message, 'john' as created_by,
'2016-08-04 01:25:06' as date, 'john' as col2,
'2016-08-04 01:25:06' as col3, NULL as col4, NULL as col5
) t
WHERE NOT EXISTS (SELECT 1
FROM test.testTable tt
WHERE tt.message = t.message AND
tt.created_by = t.created_by
);
In addition, the LIMIT 1 isn't doing anything because you only have one row.

MySQL Select unique sorted field values

I've trying to concatenate the values of 2 GROUP_CONCAT( columns ) from a single table that's been joined twice, then get the unique items from the list.
I can do all this outside of my query but if possible it would be nice to just pull the data from the DB with a JOIN and some fancy string manipulation.
Simply put, I want to produce 1,2,3,4 from selecting 1,2,3 and 1,3,4. The 1,2,3 adn 1,3,4 are the results of the GROUP_CONCAT on the twice joined table. I can get this far:
SELECT CONCAT_WS(
",",
"1,2,3",
"1,3,4"
)
Which outputs 1,2,3,1,3,4
I'd like to be able to do something like:
-- NOTE TO SKIM READERS: THIS QUERY WILL NOT WORK
SELECT
SORT_LIST(
DISTINCT
CONCAT_WS(
",",
"1,2,3",
"1,3,4"
)
)
-- NOTE TO SKIM READERS: THIS QUERY WILL NOT WORK
But I can't find anything like that in MySQL.
The 1,2,3 and 1,3,4 have already been produced with GROUP_CONCAT( DISTINCTcol)
As stated in my comment I worked out a way to achieve distinct concatenated lists of strings using a sub query:
DROP TABLE IF EXISTS `test1234`;
CREATE TABLE `test1234` (
`val` int(1),
`type` varchar(1)
);
INSERT INTO `test1234` VALUES
( 1, 'a' ),
( 2, 'a' ),
( 3, 'a' ),
( 1, 'b' ),
( 3, 'b' ),
( 4, 'b' );
SELECT GROUP_CONCAT( `val` ) AS `vals`
FROM (
(
SELECT `val` FROM `test1234` WHERE `type` = 'a'
) UNION DISTINCT (
SELECT `val` FROM `test1234` WHERE `type` = 'b'
)
) AS `test`;
DROP TABLE IF EXISTS `test1234`;
This selected 1,2,3,4

MySQL search products with their attributes

I have a MySQL database that contains products with their group/attributes/
i created a sample of data in
http://sqlfiddle.com/#!2/7d8a04/1
create table products (
id int(10),
title varchar(50)
);
create table attributes (
id int(10),
title varchar(50)
);
create table filters (
id int(10),
attribute_id int(10),
title varchar(50)
);
create table product_filters (
id int(10),
product_id int(10),
attribute_id int(10),
filter_id int(10)
);
#products
insert into products select '1', '1stphone';
insert into products select '2', '2ndphone';
#attributes
insert into attributes select '1', 'ram';
insert into attributes select '2', 'cpu';
insert into attributes select '3', 'hdd';
#filters
insert into filters select '1', '1','128MB';
insert into filters select '2', '1','256MB';
insert into filters select '3', '2','1GHz';
insert into filters select '4', '2','2GHz';
insert into filters select '5', '3','16GB';
insert into filters select '6', '3','32GB';
#product_filters
insert into product_filters select '1','1','1','2';
insert into product_filters select '2','1','2','4';
insert into product_filters select '3','1','3','6';
insert into product_filters select '4','2','1','1';
insert into product_filters select '5','2','2','3';
insert into product_filters select '6','2','3','5';
so I need to search that product (or products ) has 128MB OR 256MB RAM and 32GB HDD
If you see this link http://sqlfiddle.com/#!2/7d8a04/1 you can see my query
but I dont know why it return 0 row.
SELECT DISTINCT products.*
FROM products
JOIN product_filters ON product_filters.product_id=products.id
# where_ram_is_128MB_OR_256MB # it works !!
where ( product_filters.attribute_id=1 and product_filters.filter_id in (1,2) )
# and_where_hdd_is_32GB # not_works !!
AND ( product_filters.attribute_id=3 and product_filters.filter_id in (6) )
You need to join with product_filters separately for each attribute:
SELECT DISTINCT products.*
FROM products
JOIN product_filters AS f1 ON f1.product_id=products.id
JOIN product_filters AS f2 ON f2.product_id=products.id
WHERE ( f1.attribute_id=1 and f1.filter_id in (1,2) )
AND ( f2.attribute_id=3 and f2.filter_id in (6) )
DEMO
Your version tried to find a single row in product_filters that has both attribute IDs, which isn't possible.

How can I do this Query on SQL Server 2008 without TSQL

I'm trying to make a query but I don't know how to do it. I'm a newbie in SQL querying, so please be patient.
Here is what I have:
select
count(*), sum(time), 'peter'
from
(select *
from ACTUATION
where OPERATOR != 'peter'
and team in (select eq1.name
from TEAMWORKS eq1
where operator1 = 'peter'
or operator2 = 'peter'
or operator3 = 'peter'
or operator4 = 'peter'
or operator5 = 'peter'
or operator6 = 'peter'
or operator7 = 'peter' )) as a
This works OK, but I need to do it for every operator in the table operators and don't know how to do it.
I've tried several subqueries and groups by, but I can not make it work properly.
Kind regards
EDIT:
Let's say I have this DataBase:
create table TEAMWORKS
(
operator1 varchar(50),
operator2 varchar(50),
operator3 varchar(50),
operator4 varchar(50),
operator5 varchar(50),
operator6 varchar(50),
operator7 varchar(50),
name varchar(50)
)
insert into TEAMWORKS (operator1,operator2,name) values ('Peter', 'Paul', 'Pe-Pa')
insert into TEAMWORKS (operator2,operator3,name) values ('Peter', 'John', 'Pe-Jo')
insert into TEAMWORKS (operator1,operator4,name) values ('John', 'Paul', 'Jo-Pa')
insert into TEAMWORKS (operator5,operator6,name) values ('John', 'Peter', 'Jo-Pe')
create table OPERATORS
(
name varchar(50),
surname varchar(50)
)
insert into OPERATORS (name,surname) values ('Peter', 'Font')
insert into OPERATORS (name,surname) values ('Paul', 'Bridges')
insert into OPERATORS (name,surname) values ('John', 'Oldfield')
create table ACTUATION
(
ID int,
time int,
operator varchar(50),
team varchar(50),
description varchar(999)
)
insert into ACTUATION (ID,time,operator,team,description) values (1,30,'Peter', '','Pick flowers')
insert into ACTUATION (ID,time,operator,team,description) values (2,15,'Paul', '','Throw flowers')
insert into ACTUATION (ID,time,operator,team,description) values (3,30,'Peter', 'Jo-Pe','Pick stones')
insert into ACTUATION (ID,time,operator,team,description) values (4,5,'John', 'Jo-Pe','Throw stones')
insert into ACTUATION (ID,time,operator,team,description) values (5,15,'Paul', 'Jo-Pa','Throw tables')
insert into ACTUATION (ID,time,operator,team,description) values (6,30,'Peter', 'Pe-Pa','Pick tables')
And I need to get the time used by Every operator in table OPERATORS where he is not the main operator in Table ACTUATIONS, but part of a TEAM in the ACTUATIONS.
In the given example, I would like to get as result:
Operator #Actuations (count) Time(sum) 'Origin (only for clarifying, list not needed)
Peter 1 5 'from actuation #4
Paul 1 30 'from actuation #6
John 2 45 'form actuations #3 and #5
Hope now it's more clear
EDIT 2:
You have a working example here: http://sqlfiddle.com/#!3/91373/6/0
That's the desired result, but obviously I would not be able to use unions as I would not know the Operators.
Edit:
After OP having altered the question, here is a working query for your example:
select top 1000
o.name
, count(1)
, sum(a.time)
from OPERATORS o
left join (
select
unpvt.Operator
, unpvt.ColName
, unpvt.name
from
(select name, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from TEAMWORKS) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt
) tw on o.name = tw.Operator
left join ACTUATION a on a.team = tw.name
where a.operator != o.name
group by o.name
This returns your decired result :)
Old Post:
I don't know the structure of the database, but I've had a go at guessing.
Firstly, i create to temporary tables in T-SQL - this is done for testing.
I've previously been down-voted for using temporary tables without descriptions in answers on SO for being to complicated, so please ask if you don't understand
declare #ACTUATION table(
time datetime default getdate()
, Operator varchar(8)
, Workteam varchar(8)
)
insert into #ACTUATION (Operator, Workteam)
select 'Gunnar', 'Peter'
union all select 'Peter', 'Gunnar'
We also need the table Teamworks:
declare #TEAMWORKS table(
time datetime default getdate()
, sometext varchar(32)
, operator1 varchar(8)
, operator2 varchar(8)
, operator3 varchar(8)
, operator4 varchar(8)
, operator5 varchar(8)
, operator6 varchar(8)
, operator7 varchar(8)
)
insert into #TEAMWORKS(sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7)
select 'Blah Blah', 'Gunnar', 'Jack', 'Sam', 'Joe', 'Lee', 'Jane', 'Jim'
union all select 'More Blah', 'Bob', 'Sal', 'Phil', 'Clark', 'Jones', 'Sue', 'Peter'
union all select 'Even more Blaah', 'Im', 'Running', 'out of', 'dummy', 'names', 'Peter', 'Gunnar'
What I've done here is to create two "virtual" tables, which only consist as variables. Eg. they are recreated each time the query is run. However, I think that they are a great tool when trying to visualize.
Next step is to UNPIVOT the operators to a more normalized structure.
This is done using the following query:
select
unpvt.time
, unpvt.sometext
, unpvt.Operator
, unpvt.ColName
from
(select time, sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from #TEAMWORKS) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt;
This query should make a great starting point for further joins.
For instance, I assume that this is (partly) the result you want:
select
a.Operator
, count(1)
, max(t.time)
from #ACTUATION a
left join (
select
unpvt.Operator
, unpvt.time
from (
select time, sometext, operator1, operator2, operator3, operator4, operator5, operator6, operator7
from #TEAMWORKS
) ot
UNPIVOT (
Operator FOR ColName IN (operator1, operator2, operator3, operator4, operator5, operator6, operator7)
) as unpvt
) t on a.Workteam = t.Operator
where a.Operator != t.Operator
group by a.Operator