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.
Related
I have a matching algorithm that I need to build on a large dataset in a SQL Server 2008 database. This is a minimal example of the kind of thing I need.
Say I have table1 and table2 each with just four columns, unique_id, col1, col2 and col3.
CREATE TABLE table1
(
unique_id VARCHAR(4),
col1 INT,
col2 INT,
col3 INT
);
INSERT INTO table1
VALUES ('ADAF', '2', '4', '17'),
('WSDA', '1', null, '12');
GO
CREATE TABLE table2
(
unique_id VARCHAR(4),
col1 INT,
col2 INT,
col3 INT
);
INSERT INTO table2
VALUES ('QWAS', '2', '4', '17'),
('FDFR', '3', '4', '17'),
('LKPY', '2', '4', null),
('FGDA', '1', null, '12'),
('GAPU', '1', '3', '12');
For all the records in table1, I want to return the unique IDs in table1 and the unique_ids in table2 where at least two out of three of the variables in col1, col2 and col3 are the same. It is OK if one of the variables does not match because it contains a null, but if any of the three columns contain a non-null value that does not match its counterpart in the other table then the match is automatically invalidated.
So in this example in table1 record ID ADAF will return QWAS (exact match) and LKPY as the non-null values match, but not FDFR because there is a non-match in col1.
WSDA will return FGDA and also GAPU as the null to 3 does not count as a mismatch.
I can solve this (inefficiently) by using a union query to get matches on the three columns into a temp table then linking this back to the original data with joins using another union query to get any invalidated matches, then running a query returning all matches, net of any invalidated matches.
However, my real world application needs me to match 3 out of 6 variables, with approximately 10 million rows in my record set matching to a much larger set of possible matches, so I need something more efficient.
You can get the results you want by JOINing the tables on matching values on each column while also allowing for NULL values to act as a match, and then counting the number of actual matches and requiring that to be at least 2:
SELECT t1.unique_id AS t1_id, t2.unique_id AS t2_id
FROM table1 t1
JOIN table2 t2 ON (t1.col1 = t2.col1 OR t1.col1 IS NULL OR t2.col1 IS NULL)
AND (t1.col2 = t2.col2 OR t1.col2 IS NULL OR t2.col2 IS NULL)
AND (t1.col3 = t2.col3 OR t1.col3 IS NULL OR t2.col3 IS NULL)
AND CASE WHEN t1.col1 = t2.col1 THEN 1 ELSE 0 END
+ CASE WHEN t1.col2 = t2.col2 THEN 1 ELSE 0 END
+ CASE WHEN t1.col3 = t2.col3 THEN 1 ELSE 0 END
>= 2
Output (for your sample data)
t1_id t2_id
ADAF QWAS
ADAF LKPY
WSDA FGDA
WSDA GAPU
Demo on dbfiddle
I have below table STORAGE_CAPACITY with me.
CREATE TABLE STORAGE_CAPACITY(DATE_TIME DATETIME,COL1 INT,COL2 INT,COL3 INT,COL4 INT);
INSERT INTO STORAGE_CAPACITY values(SYSDATE(),1,2,3,4);
INSERT INTO STORAGE_CAPACITY values(SYSDATE(),1,2,3,4);
INSERT INTO STORAGE_CAPACITY values(SYSDATE(),4,5,6,7);
INSERT INTO STORAGE_CAPACITY values(SYSDATE(),4,5,8,9);
INSERT INTO STORAGE_CAPACITY values(SYSDATE(),1,2,3,4);
SELECT * FROM storage_capacity
Now what i want is if two consecutive rows have same element in col1 to col4 then i only want older one.
And if same row happened in future then i want that row.
So my expected O/P
DATE_TIME, COL1, COL2, COL3, COL4
'2017-08-16 16:37:02', '1', '2', '3', '4'
'2017-08-16 16:37:18', '4', '5', '6', '7'
'2017-08-16 16:37:26', '4', '5', '8', '9'
'2017-08-16 16:37:57', '1', '2', '3', '4'
Assuming that the first column defines the ordering, you can use variables for this:
select t.*
from (select t.*,
(#rn := if(#cols = concat_ws(',', col1, col2, col3, col4), #rn + 1,
if(#cols := concat_ws(',', col1, col2, col3, col4), 1, 1)
)
) as rn
from t cross join
(select #cols := '', #rn := 0) params
order by t.date_time
) t
where rn = 1;
Note: To establish the order of insert, it is safer to use an auto_increment columns rather than a datetime column. Multiple rows can be inserted in the table with the same datetime value.
i have some data in the MySQL table like this:
2017-02-01: 'A': 'K1': 100
2017-02-01: 'A': 'K2': 200
2017-02-01: 'B': 'K1': 300
2017-02-02: 'A': 'K1': 110
2017-02-02: 'A': 'K2': 210
2017-02-02: 'B': 'K1': 310
i need to insert new data only if last (by date) value is not equal with new.
for example: insert new 400 if last [A:K1]<>400
i use 2 queries now for this job, but it's very slow to insert it:
$res=mysql_query("select * from `table` where `col1`='A' and `col2`='K1' order by 'date' desc limit 1");
$tkol=0;
if($res){while($r=mysql_fetch_assoc($res)){$tkol=$r[0]['col3']; break;}}
if($tkol!=$newVal){
$q="INSERT INTO `table` (`date`,`col1`,`col2`,`col3`) VALUES ('2017-02-10','A','K1',$newVal)";
mysql_query($q);
}
how to write my task in 1 mysql-query like "INSERT ... IF ..."?
Please, help me.
Try to use INSERT INTO SELECT syntax:
INSERT INTO `table` (`date`,`col1`,`col2`,`col3`)
SELECT DISTINCT '2017-02-10', 'A', 'K1', $newVal
FROM `table` t1
JOIN (
SELECT MAX(`date`) AS maxdate, `col1`, `col2`
FROM `table`
WHERE `col1` = 'A'
AND `col2` = 'K1'
) t2 ON t1.`col1` = t2.`col1` AND t1.`col2` = t2.`col2` AND t1.`date` = t2.`maxdate`
WHERE t1.`col1` = 'A'
AND t1.`col2` = 'K1'
AND t1.`col3` <> $newVal
use significant column as unique key and use REPLACE instead of INSERT.
OR
You can use insert ... from select ... where oldval <> newval;
select will not have "from" and values will be straightly written into it from webserver.
$q="INSERT INTO `table` (`date`,`col1`,`col2`,`col3`) select ".$date.", ".$a.", ".$b.", ".$c." WHERE not exists (select 1 from `table` where col1 = $a ... and date = select(max) date from table)";
And, remember about input validation!
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);
I'm trying to insert a record if a sum of 3 user columns from 2 tables exceeds a constant.
I've searched all over, found you can't put user variables in IFs, WHERE's etc. Found you can't put SUMs in IFs, WHERE's etc. I'm at a total loss. Here's an example of my earlier bad code before unsuccessfully trying to use SUMs in WHEREs, if it helps:
SELECT SUM(num1) INTO #mun1 FROM table1 WHERE user = '0';
SELECT SUM(num2) INTO #mun2 FROM table1 WHERE user = '0';
SELECT SUM(num3) INTO #mun3 FROM table2 WHERE column1 = 'd' AND user = '0';
SET #mun4 = #mun1 - #mun2 - #mun3;
INSERT INTO table2 (user, column1, column2) VALUES ('0', 'd', '100') WHERE #mun4 >= 100;
Try this:
INSERT INTO table2 (user, column1, column2)
select '0', 'd', '100'
from dual
where (SELECT SUM(num1 + num2) FROM table1 WHERE user = '0') +
(SELECT SUM(num3) FROM table2 WHERE column1 = 'd' AND user = '0') > 100;
This is a case of the general solution for a "insert if condition" problem:
insert into ... select ... where condition
The select will only return rows if the condition is true, and importantly, will return no rows if false - meaning the insert only happens if the condition is true, otherwise nothing happens.
This is same as #Bohemian's answer, but you got to add a LIMIT clause to stop inserting multiple records, since select clause may return multiple records
INSERT INTO table2 (user, column1, column2)
SELECT '0', 'd', '100'
FROM dual
WHERE
(SELECT SUM(num1 - num2) FROM table1 WHERE user = '0')
(SELECT SUM(num3) FROM table2 WHERE column1 = 'd' AND user = '0') >
100
LIMIT 1