I have read that the function "values ()" is being removed in a future version - and I am therefore looking for an alternative - to if you have an "insert into select" command.
I have searched a lot on the web, but do not think I have found an answer - when it comes to "select" ...
Let's say I have 2 tables (t1 and t2) and some summations need to be written in t1 from t2.
t1:
product_id
quantity
total_value
1
3
100
2
2
80
t2:
product_id
value
1
50
1
50
1
50
2
40
2
50
Normally I would do it as follows:
insert into t1 (product_id,quantity,total_value)
select product_id,count(*),sum(value)
from t2 group by product_id on duplicate key update quantity=values(quantity),total_value=values(total_value)
This will give the following result:
t1:
product_id
quantity
total_value
1
3
150
2
2
90
But how do I do something similar if I can not use "values ()" ..?
It is of course an option to delete the relevant rows in t1 first - to avoid having a "duplicate key" at all - but is there no better way ..?
Thanks.
Normally I would do it as follows:
Use SELECT aliases:
insert into t1 (product_id, quantity, total_value)
select *
FROM ( SELECT product_id AS p, count(*) AS q, sum(value) AS s
from t2
group by p ) src
on duplicate key update quantity=q, total_value=s
But how do I do something similar if I can not use "values ()" ..?
The same
insert into t1 (product_id, quantity, total_value)
VALUES (1, 10, 100) AS x(p, q, s)
on duplicate key update quantity=q, total_value=s
fiddle
Related
I've a sample table table1:
id transaction_number net_amount category type
1 100000 2000 A ZA
2 100001 4000 A ZA
3 100002 6000 B ZB
I've a sample table table2:
id transaction_number net_amount category type
1 100002 6000 B ZB
How do I insert unique records that are not in table2, but present in table1?
Desired result:
id transaction_number net_amount category type
1 100002 6000 B ZB
2 100000 2000 A ZA
3 100001 4000 A ZB
INSERT INTO table2 ( transaction_number, net_amount, category, type )
(
/* Rows in table1 that don't exist in table2: */
SELECT ( table1.transaction_number, table1.net_amount, table1.category, table1.type )
FROM table1
LEFT JOIN table2 ON ( table1.transaction_number = table2.transaction_number )
WHERE table2.transaction_number IS NULL
)
If you don't want to duplicate transaction numbers in table2, then create a unique index or constraint on that column (or the columns you want to be unique). Let the database handle the integrity of the data:
alter table table2 add constraint unq_table2_transaction_number
unique (transaction_number);
Then use on duplicate key update with a dummy update:
insert into table2 (transaction_number, net_amount, category, type)
select transaction_number, net_amount, category, type
from table1
on duplicate key update transaction_number = values(transaction_number);
Why do I recommend this approach? First, it is thread-safe, so it works even when multiple queries are modifying the database at the same time. Second, it puts the database in charge of data integrity, so the transactions will be unique regardless of how they are changed.
Note that the most recent versions of MySQL have deprecated this syntax in favor of the (standard) on conflict clause. The functionality is similar, but I don't think those versions are widespread.
Try this
INSERT INTO table2 (transaction_number,net_amount,category,type)
(SELECT transaction_number,net_amount,category,type from table1) ON DUPLICATE KEY UPDATE
net_amount=VALUES(net_amount),category=VALUES(category),type=VALUES(type);
Usw not exists as follows:
Insert into table2
Select t1.*
From table1 t1
Where not exists
(Select 1 from table2 t2
Where t1.transaction_number = t2.transaction_number)
This question stumps me. I have a database with a table that has a primary key that consists of two fields. In the end I require that the primary key only be one field, but I need to delete the duplicate entries from the table.
In other words the table has:
PRIMARY KEY (`field1`, `field2`)
There are entries that have duplicate field1 and different field2. So I have entries like this:
field1 | field2
1 | 1
1 | 2
2 | 1
2 | 2
3 | 1
4 | 1
I want to delete 1 of each of those entries that have duplicates on field1.
How can I do this with MySQL / SQL?
I think this will work in your case,
DELETE t1 FROM table t1
INNER JOIN table t2
WHERE t1.id > t2.id
AND t1.field1 = t2.field1
In this query I am joining the same table and picking duplicate values of field1 with different id and removing those.
Hope this works!!
I dont know how the delete from table needs to be specified in the mysql syntax but essentially you are trying to remove the second entry for the field1 for each of its unique value. So in some way if you are able to retrieve those records and pass them as select statements under your delete from table clause it should work.
For instance, here is the query that would select 2nd row for each value of field1 if it is repeated
select field1, field2
from
(
select *, count(*) over (partition by field1) as ct
, rank() over (partition by field1 order by field2 desc) as rn
from temp
) where rn = 1 and ct = 2
In your case it would return below records
field1 field2
1 2
2 2
So then all you need to do is have a delete from table clause at the top of that select statement.
NOTE - I have tried a solution without a join and hence I maintain these 2 analytical functions.
For instance this works in something like BigQuery -
delete from TABLE where concat(field1, field2) in
(
select concat(field1, field2)
from
(
select *, count(*) over (partition by field1) as ct
, rank() over (partition by field1 order by field2 desc) as rn
from TABLE
) where rn = 1 and ct = 2
)
I am sure this has been answered before, but I am just learning mysql and so I do not know how to properly search for the solution. I have two tables:
Table1 Table2
id email id domain
-- ---- -- ----
1 name#domain1.com 1 domain1.com
2 name#domain2.com 2 domain4.com
3 name#domain3.com
4 name#domain4.com
Using the emails in Table1, I would like to return the domains that do not exist in table2, and then write them to Table2, so I have a complete, unique list of domains in Table 2.
Table1 Table2
id email id domain
-- ---- -- ----
1 name#domain1.com 1 domain1.com
2 name#domain2.com 2 domain4.com
3 name#domain3.com 3 domain2.com
4 name#domain4.com 4 domain3.com
You can achieve this using a WHERE NOT IN with a sub query
INSERT INTO Table2 ( domain )
SELECT DISTINCT SUBSTRING_INDEX(email,'#',-1)
FROM Table1
WHERE SUBSTRING_INDEX(email,'#',-1) NOT IN (SELECT domain FROM Table2)
make the domain names a unique key in table2 then INSERT IGNORE select distinct substring() etc from table1
Alter table_2
add unique key k1(domain);
insert ignore into table_2(domain)
select distinct substring_index(email,'#',-1)
from table_1;
Where IGNORE will err ignore errors like duplicates.
I have 2 tables:
stock:
pid name qty
--- ---- ---
1 aaaa 2
2 bbbb 3
1 aaaa 5
3 cccc 1
2 bbbb 2
stock_total:
pid name total_qty
--- ---- ---------
I can insert rows from stock table with the total qty to stock_total using this query
INSERT INTO stock_total (pid, name, total_qty)
SELECT pid, name, SUM(qty)
FROM stock
GROUP BY pid, name
The problem is, I will run the SQL above via cron job. So on the next execution, the SQL should UPDATE existing product and INSERT non-exist products.
It would be very inefficient if I loop over the SELECT results, check each row if exists in stock_total and do the INSERT or UPDATE.
Is there any simpler way for achieving this? perhaps by modifying the SQL above. Thanks.
Use DUPLICATE KEY UPDATE:
INSERT INTO TABLENAME(col1, col2)
VALUES (#value, ‘yyy’)
ON DUPLICATE KEY UPDATE col1 = #value
This for the update:
UPDATE stock_total
SET total_qty = SUM(s.qty)
FROM stock_total st
INNER JOIN stock s
ON st.pid = s.pid
AND st.name = s.name
WHERE s.pid = st.pid
GROUP BY s.pid
And this for the insert:
INSERT INTO stock_total
SELECT s.pid, s.name, SUM(s.qty)
FROM stock s
WHERE s.pid NOT IN (SELECT pid FROM stock_total)
GROUP BY s.pid, s.name
Should be fine, give it a try.
Why dont you call a Stored Procedure from the job?
In the SP in the block catch the DUPLICATE KEY exception and UPDATE. If no EXCEPTION is thrown it will INSERT.
merge is what you are searching for. Use it as follows -
merge into stock_total s " +
"using (select ? pid, ? name, ? total_qty from dual) d " +
"on (s.pid = d.pid and s.name = d.name and s.total_qty = d.total_qty) " +
"when matched then " +
"update set s.pid= d.pid, s.name = d.name, s.total_qty = d.total_qty" +
"when not matched then " +
"insert (pid, name, total_qty) " +
"values(d.pid, d.name, d.total_qty)" ;
EDIT(for mySQL):
MERGE INTO table_name WITH (HOLDLOCK) USING table_name ON (condition)
WHEN MATCHED THEN UPDATE SET column1 = value1 [, column2 = value2 ...]
WHEN NOT MATCHED THEN INSERT (column1 [, column2 ...]) VALUES (value1 [, value2 ...])
After some googling and experimenting with the answers here, I came up with this solution. It turns out that MySQL supports REPLACE INTO... and ...ON DUPLICATE KEY UPDATE. So my query would be like this:
REPLACE INTO stock_total
SELECT pid, name, SUM(qty)
FROM stock
GROUP by pid, name
or,
INSERT INTO stock_total
SELECT pid, name, SUM(qty)
FROM stock
GROUP by pid, name
ON DUPLICATE KEY UPDATE total_qty=VALUES(total_qty)
If a row exists on stock_total, the first query will DELETE then INSERT the new row,
and the second query will UPDATE the existing row.
Both query will only work if the table has a primary key or unique index:
CREATE TABLE stock_total (
pid INT NOT NULL,
name VARCHAR(20) NOT NULL,
total_qty INT NOT NULL,
UNIQUE (pid, name)
);
Documentation:
REPLACE syntax
INSERT ... ON DUPLICATE KEY UPDATE syntax
How I can create an SQL command to delete all rows from table where I have two or more specific columns with the same value and still I don't lose that row, only the duplicates?
For example:
Id value1 value2
1 71 5
2 8 8
3 8 8
4 8 8
5 23 26
Id2, Id3 and Id4 have same value1 and value2.
I need to delete all duplicate rows like (Id3 and Id4) or (Id2 and Id4) or (Id2 and Id3)
delete t
from table1 t
inner join table1 t2
on t.id>t2.id and t.value1=t2.value1 and t.value2=t2.value2
Since MySQL allows ungrouped fields in queries:
CREATE TEMPORARY TABLE ids AS
(SELECT id
FROM your_table
GROUP BY value1, value2);
DELETE FROM your_table
WHERE id NOT IN (SELECT id FROM ids);
What you can do is copy the distinct records into a new table by:
select distinct * into NewTable from MyTable