MySql Query - INSERT INTO command but only without duplicates - mysql

I have this workable query which is inserting proper data into 'selections' table according to some conditions:
INSERT INTO selections (auctionid, selections.order)
VALUES
((SELECT id FROM auctions, game WHERE auctions.BetfairMark = game.BetfairMarketID), 1,
((SELECT id FROM auctions, game WHERE auctions.BetfairMark = game.BetfairMarketID), 2,
((SELECT id FROM auctions, game WHERE auctions.BetfairMark = game.BetfairMarketID), 3
but my problem is how to improve this query to prevent getting same duplicates in table when running this query?
Selections table have 3 columns: id, auctionid, order where id is autoincrement number generated for each new record.
So auctionid and order shouldn't be the same values in record.

Add a UNIQUE INDEX to the (auctionid, order) pair.
ALTER TABLE selections ADD UNIQUE index_name (`auctionid`, `order`)
And when you insert you can use INSERT IGNORE INTO ... so that it ignores duplicates instead of throwing an error. (Useful when you batch insert and the duplicates are expected)

SOLVED!
Created 3 separated queries for each row, working for now!
So with added UNIQUE INDEX to the (auctionid, order) pair have this workable code:
INSERT IGNORE INTO
selections
(
selections.auctionid,
selections.order,
selections.title,
startamount
)
SELECT
auctions.id,
1,
PlayerA,
0.01
FROM
auctions, game
WHERE
auctions.BetfairMark = game.BetfairMarketID
;
INSERT IGNORE INTO
elections
(
selections.auctionid,
selections.order,
selections.title,
startamount
)
SELECT
auctions.id,
2,
PlayerB,
0.01
FROM
auctions, game
WHERE
auctions.BetfairMark = game.BetfairMarketID
;
INSERT IGNORE INTO
selections
(
selections.auctionid,
selections.order,
selections.title,
startamount
)
SELECT
auctions.id,
3,
'third text',
0.01
FROM
auctions, game
WHERE
auctions.BetfairMark = game.BetfairMarketID
;

Related

Insert into multiple tables only if record doesn't exist in primary table

I don't seem to understand IF statements in SQL very well.
I have two tables, one called event_headers and one called event_records. Each event in has a single entry in the event_header table and at least one record in the event_records table.
I'm running a script in c# that reads SQL files that will insert into each table, but I'm running into a problem with duplicates. I can eliminate the duplicates in the event_header table by using INSERT IGNORE. The trouble I have is I want to be able to skip inserting into the event_records table if there is already an entry in the event_header table.
EXAMPLE:
INSERT INTO `event_headers` (`session_id`, [...] ) VALUES ('89131', [...] );
INSERT INTO `event_records` (`event_header_session_id`, [...] )
VALUES
('89131', [...] ),
('89131', [...] ),
('89191', [...] );
(In truth, I have a third table that also has records that get updated, but this illustrates the point).
I want to only run the INSERT statements if the event_headers.session_id does not exist.
You must check does the 1st insertion inserts the row. You may do this, for example, using ROW_COUNT() which returns the amount of rows really altered in previous statement. The only point - you must use INSERT .. SELECT for 2nd insertion because INSERT .. VALUES does not allow WHERE clause:
INSERT IGNORE INTO main_table VALUES (...);
INSERT INTO slave_table
SELECT *
FROM ( SELECT ... UNION ALL SELECT ... ) slave_data;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0668b71ddcdc67180b3ed54acb562931
Both statements must be executed as a batch (in the same connection, without any other statement between them).
Only one row must be inserted into main table.
But stored procedure which checks the presence in main table and inserts only when no such row is preferred.
Instead of just using VALUES, use a select:
INSERT INTO `event_records` (`event_header_session_id`, col_a, col_b, col_c )
SELECT event_header_session_id, col_a, col_b, col_c
FROM (
SELECT NULL event_header_session_id, NULL col_a, NULL col_b, NULL col_c WHERE 0
UNION ALL
VALUES
ROW('89131', 1,2,3 ),
ROW('89131', 2,3,4 ),
ROW('89191', 3,4,5 );
) new_rows
WHERE NOT EXISTS (
SELECT 1
FROM event_headers
WHERE event_headers.session_id=new_rows.event_headers_session_id
);
The SELECT NULL...UNION ALL is the most portable way I know to name the columns of a VALUES table constructor. On mariadb, omit the ROWs.

MySQL Stop Insert based on field value

I want to do an insert ignore if a column has a specific value.
Say I have a simple table that records changes to a PO over time. Each time the PO is updated, I need to insert a record on this table:
PONum | POLine | submittedBy | ... other columns
100 1 initial-value
100 1 TB
100 2 initial-value
On a PHP page I check for the existence of the PO number in this table. If there isn't one, I insert all the PO lines I find from another table. I set the submittedBy name to "initial-value".
Now later on, say PO Line 3 is added. I want to run through my check again and only insert the new record for line 3 if there isn't already one that has line 3 with a submittedBy of initial-value
INSERT IGNORE INTO PODetailCL (PONum, POLine, submittedBy, ... )
VALUES (100, 1, 'TB', ... ),
(100, 2, 'TB', ...),
(100, 3, 'initial-value', ...)
WHERE submittedBy <> 'initial-value' -- <- something like this but not sure of the syntax
Try using conditional insert multiple rows:
INSERT INTO PODetailCL(PONum, POLine, submittedBy, ... )
SELECT (100, 1, 'TB', ... ), (100, 2, 'TB', ...),(100, 3, 'initial-value', ...)
FROM PODetailCL
WHERE EXISTS (SELECT * FROM PODetailCL WHERE submittedBy <> 'initial-value')
I was able to use a virtual column and then add a unique constraint on that column. After that I can use INSERT IGNORE. (Virtual columns are only available in MySQL version 5.7 or later.)
ALTER TABLE porelcl
ADD COLUMN initialCheck BIT GENERATED ALWAYS
AS (CASE WHEN submittedBy = 'initial-value' THEN b'1' ELSE NULL END)
then after that:
ALTER TABLE porelcl ADD UNIQUE initial_check_index (PONum, POLine, PORelNum, initialCheck)
Now when my code runs through the check again, if tries to insert a duplicate record: SomePO, SomePOLine, SomePORelNum & 'initial-value' the insert won't take place, which is what I need.

Mysql database change ordering of records

Here I have data in mysql database that is reversed in order. How to change the ordering so that default ordering that is ASC is reversed.
Primary field is ID. ANd ID is auto_increment. I need to change the ID fields in reverse order for each records.
For example. Let's assume I have 2 records in table.
ID field
1 field1
2 field2
I want to have field2 to have ID 1 and field1 to have ID 2
You could do:
ALTER TABLE `table` ORDER BY `ID` DESC
but its bad database design
its against First normal form
or you can export the entire table in script file. "sql" and once the script in hand you can put in order all the (INSERT INTO) backwards. It takes a few minutes but it works
1: generate script from your base..you can use phpmyadmin or console line mysql
2. reverse the insert command
Base script Before:
INSERT INTO example (name, age) VALUES('Sandy Smith', '21' )
INSERT INTO example (name, age) VALUES('peter brad', '38' )
INSERT INTO example (name, age) VALUES('mike alves', '24' )
base script After:
INSERT INTO example (name, age) VALUES('mike alves', '24' )
INSERT INTO example (name, age) VALUES('peter brad', '38' )
INSERT INTO example (name, age) VALUES('Sandy Smith', '21' )
it is a slower but can it clean
OHTER solution ->
You can then try something like this: - Create a new table with the information from the original table by retrieving all the id and reversing with ORDER BY!
CREATE TABLE newtable SELECT ID, row1, row2, row3, row4, row5 FROM oldtable ORDER BY id DESC ;
And then delete the old table It should work without problem

mysql insert value if it doesn't exist

I'm trying to insert an ingredient to an ingredients table if it doesn't exist.
I'm using the following syntax:
INSERT INTO ingredient(Name)
(
SELECT 'ingName' FROM dummytable WHERE
(SELECT count(*) FROM ingredient WHERE Name = 'ingName')=0)
This does not seem to work (0 rows affected), even though the SELECT query seem to return the desired result (an entry which contains "ingName").
The "ingredient" table has 2 columns: Name, id (id is auto incremented)
Thanks,
Li
Its better to add unique index on the name column:
ALTER TABLE `ingredient` ADD UNIQUE(`Name`)
After doing that you can use INSERT IGNORE:
INSERT IGNORE INTO `ingredient` ... /* anything */
That's because your inner query SELECT count(*) FROM ingredient WHERE Name = 'ingName' is returning a value > 0 and hence the upper query SELECT 'ingName' FROM dummytable WHERE is not selecting any rows and so no insert is happening.
I tried the same with a test table having 2 column name|value and it did worked fine
INSERT INTO test1(name) (
SELECT 'name' FROM test2 WHERE
(
SELECT count(*) FROM test2 WHERE name = 'bilboa'
)
=0
)
Inserted 2 rows with value name cause that's what I am selecting in select query and my test table 2 rows.

Update multiple rows with known keys without inserting new rows if nonexistent keys are found

Let's imagine that we have table items...
table: items
item_id INT PRIMARY AUTO_INCREMENT
title VARCHAR(255)
views INT
Let's imagine that it is filled with something like
(1, item-1, 10),
(2, item-2, 10),
(3, item-3, 15)
I want to make multi update view for this items from data taken from this array [item_id] => [views]
'1' => '50',
'2' => '60',
'3' => '70',
'5' => '10'
IMPORTANT! Please note that we have item_id=5 in array, but we don't have item_id=5 in database.
I can use INSERT ... ON DUPLICATE KEY UPDATE, but this way image_id=5 will be inserted into talbe items. How to avoid inserting new key? I just want item_id=5 be skipped because it is not in table.
Of course, before execution I can select existing keys from items table; then compare with keys in array; delete nonexistent keys and perform INSERT ... ON DUPLICATE KEY UPDATE. But maybe there is some more elegant solutions?
Thank you.
You may try to generate a table of literals and update items by joining with the table:
UPDATE items
JOIN (SELECT 1 as item_id, 50 as views
UNION ALL
SELECT 2 as item_id, 60 as views
UNION ALL
SELECT 3 as item_id, 70 as views
UNION ALL
SELECT 5 as item_id, 10 as views
) as updates
USING(item_id)
SET items.views = updates.views;