SQL - How to make a conditional INSERT - mysql

Using only MySQL, I'm seeing if it's possible run an insert statement ONLY if the table is new. I successfully created a user variable to see if the table exists. The problem is that you can't use "WHERE" along with an insert statement. Any ideas on how to get this working?
// See if the "country" table exists -- saving the result to a variable
SELECT
#table_exists := COUNT(*)
FROM
information_schema.TABLES
WHERE
TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'country';
// Create the table if it doesn't exist
CREATE TABLE IF NOT EXISTS country (
id INT unsigned auto_increment primary key,
name VARCHAR(64)
);
// Insert data into the table if #table_exists > 0
INSERT INTO country (name) VALUES ('Afghanistan'),('Aland Islands') WHERE 0 < #table_exists;

IF #TableExists > 0 THEN
BEGIN
INSERT INTO country (name) VALUES ('Afghanistan'),('Aland Islands');
END

Use an if statement instead of the where clause:
http://dev.mysql.com/doc/refman/5.0/en/if-statement.html

Related

What is the syntax for input parameters (variables) in a MySQL query?

I was trying to pass parameter to my Query using MySQL as you can see in the code below. but it gives me No Records always .... any advise why?>
create table DemoTable
(
Id int,
FirstName varchar(20),
LastName varchar(20)
);
insert into DemoTable values(10,'Carol','Taylor');
select * from DemoTable;
set #myId:=10;
select *from DemoTable where Id=#myId;
0 ROWS SELECTED

Select all tables with same columns by suffix and merging them into new one

I have an arbitrary set of tables with exactly the same structure (columns) and all of the tables have the same suffix _data.
What I've tried:
CREATE TABLEglobal_dataAS SELECT * FROM (SELECT * FROMv_dataUNION ALL SELECT * FROMx_dataUNION ALL SELECT * FROMz_dataUNION ALL SELECT * FROMd_data) X GROUP BY ('id') ORDER BY 1
But as a result i'me getting only one single row even without auto increment colimn, but I need all the rows that exists in each of the table snd with autoincrement column.
So what I need is an SQL query for:
Select all tables by suffix.
Create a new one table with merged table values, where duplicates
should be skipped, and the remaining unique values needs to by merged into a
new one.
In result table should be id column with Unique and AutoIncrement attributes.
This answer uses a prepared statement, lots of people here will give you loads of grief about it, so make sure you are aware of the risks of SQL injection..
-- Create some tables, drop them if they exist already.
DROP TABLE IF EXISTS Table1_Data;
CREATE TABLE Table1_Data
(
Id INTEGER,
StoredValued VARCHAR(10)
);
DROP TABLE IF EXISTS Table2_Data;
CREATE TABLE Table2_Data
(
Id INTEGER,
StoredValued VARCHAR(10)
);
DROP TABLE IF EXISTS Table3_Data;
CREATE TABLE Table3_Data
(
Id INTEGER,
StoredValued VARCHAR(10)
);
DROP TABLE IF EXISTS Table4_Data;
CREATE TABLE Table4_Data
(
Id INTEGER,
StoredValued VARCHAR(10)
);
DROP TABLE IF EXISTS Result;
CREATE TABLE Result
(
Id INTEGER,
StoredValued VARCHAR(10)
);
-- Insert some data into the tables
INSERT INTO Table1_Data VALUES (1,'Test'),(2,'Testy'),(3,'Testing');
INSERT INTO Table2_Data VALUES (1,'Foo'),(2,'Fooby'),(3,'Foober');
INSERT INTO Table3_Data VALUES (1,'Bar'),(2,'oobar'),(3,'Barbo');
INSERT INTO Table4_Data VALUES (1,'Bar'),(2,'Testy'),(3,'JubJub');
-- Create a statement to execute
SELECT CONCAT('INSERT INTO Result',GROUP_CONCAT(' SELECT * FROM ',TABLE_SCHEMA,'.',TABLE_NAME SEPARATOR ' UNION ')) INTO #query
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME LIKE '%_Data';
-- Execute the statement
PREPARE stmt1 FROM #query;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
-- Get the results from our new table.
SELECT *
FROM Result;

Mysql Select row, update values and insert into another table

I have a temporary table with some rows:
$query = "CREATE TEMPORARY TABLE {$tn} (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(255) NOT NULL,
`title` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB";
I would like to select each row in this table, nulify id, update 'type' (for example) and insert whole selected row into another table (which has the same columns as this table).
I tried this but I am getting an error near SET ( You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SET )
foreach ($ids as $id) {//this is each id in temp table
$query = "INSERT INTO $another_table
SELECT * FROM {$tn} WHERE id='$id'
SET id=NULL, type='foo'";
$result = $conn->query($query) or die(mysqli_error($conn));
}
I am not a PHP guru, but this is the syntax you should be following. You may select any number of constants you wish from a table.
INSERT INTO $another_table (id, type, title)
SELECT NULL, 'foo', title
FROM {$tn}
WHERE id = '$id';
This assumes that the other destination table uses the same name for its columns as your first table. If not, then you will have to change the first line of my query.
Note that you should ideally be using a prepared statement here.
If both your tables have the SAME amount of columns, with the same order, and you want to avoid listing each and every column, You could just copy the entry and updated the changed value within the same transaction:
START TRANSACTION;
INSERT INTO table2 SELECT * FROM table1 WHERE id = 57;
UPDATE table2 SET columnYouWantToChange="New Value" WHERE id = 57;
COMMIT;
But maybe you should OUTLINE, what you are trying to achieve? having 2 tables with identical columns "smells" like bad design. Maybe you'd better use the same table along with revision numbers of your data row?
Your SQL is not valid, You have an insert statement with a set statement in it.
All you need is a basic INSERT SELECT this is also no need for the for loop.
INSERT INTO $another_table (id, type, title)
SELECT id, 'foo', title
FROM {$tn}
You can do the set statement as an update after inserting all rows if that is easier to get you head around.
UPDATE $another_table SET id = NULL
https://dev.mysql.com/doc/refman/8.0/en/insert-select.html
FYI if you want SET many or all the columns from a table with the same column names this query run on information_schema will generate the most tedious part of the code for you:
select concat('target.', column_name ,' = ','source.', column_name ,', ') as line
from `columns`
where `columns`.table_name = 'target';

How do I insert data into a table (and return it) when a select statement outputs no rows?

I have a MySql table that is created like this;
CREATE TABLE test_contacts
(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(16) NOT NULL,
databit int NOT NULL
);
CREATE UNIQUE INDEX test_contacts_name_uindex ON test_contacts (name);
When I want to retrieve data i do SELECT * FROM test_contacts WHERE name = '{name}';
In my current java application I am doing the following: (pseudocode)
Object result = SELECT * FROM test_contacts WHERE name = '{name}';
if (result == null) {
INSERT INTO test_contacts (`name`, `databit`) VALUES ('{name}', 2);
result = SELECT * FROM test_contacts WHERE name = '{name}';
}
Is there a way to compact these 3 database calls into 1 statement that always returns a row for the specified name? (I need the id that is inserted)
Since you have a unique index anyway, instead of checking in your code, if your first select had any result, you simply do
INSERT IGNORE test_contacts (`name`, `databit`) VALUES ('{name}', 2);
read more about it here
Then you get the id with
SELECT LAST_INSERT_ID();
read more about it here

Copy row but with new id

I have a table "test" with an auto incremented id and an arbitrary number of columns.
I want to make a copy of a row in this table with all columns the same except for the id of course.
Is there a way to do this without naming all columns?
I thought INSERT... SELECT... ON DUPLICATE KEY would help me until I realised that it never makes an INSERT ON DUPLICATE, it just updates the existing row.
Let us say your table has following fields:
( pk_id int not null auto_increment primary key,
col1 int,
col2 varchar(10)
)
then, to copy values from one row to the other row with new key value,
following query may help
insert into my_table( col1, col2 ) select col1, col2 from my_table where pk_id=?;
This will generate a new value for pk_id field and copy values from col1, and col2 of the selected row.
You can extend this sample to apply for more fields in the table.
UPDATE:
In due respect to the comments from JohnP and Martin -
We can use temporary table to buffer first from main table and use it to copy to main table again.
Mere update of pk reference field in temp table will not help as it might already be present in the main table. Instead we can drop the pk field from the temp table and copy all other to the main table.
With reference to the answer by Tim Ruehsen in the referred posting:
CREATE TEMPORARY TABLE tmp SELECT * from my_table WHERE ...;
ALTER TABLE tmp drop pk_id; # drop autoincrement field
# UPDATE tmp SET ...; # just needed to change other unique keys
INSERT INTO my_table SELECT 0,tmp.* FROM tmp;
DROP TEMPORARY TABLE tmp;
This works in MySQL all versions and Amazon RDS Aurora:
INSERT INTO my_table SELECT 0,tmp.* FROM tmp;
or
Setting the index column to NULL and then doing the INSERT.
But not in MariaDB, I tested version 10.
THIS WORKS FOR DUPLICATING ONE ROW ONLY
Select your ONE row from your table
Fetch all associative
unset the ID row (Unique Index key)
Implode the array[0] keys into the column names
Implode the array[0] values into the column values
Run the query
The code:
$qrystr = "SELECT * FROM mytablename WHERE id= " . $rowid;
$qryresult = $this->connection->query($qrystr);
$result = $qryresult->fetchAll(PDO::FETCH_ASSOC);
unset($result[0]['id']); //Remove ID from array
$qrystr = " INSERT INTO mytablename";
$qrystr .= " ( " .implode(", ",array_keys($result[0])).") ";
$qrystr .= " VALUES ('".implode("', '",array_values($result[0])). "')";
$result = $this->connection->query($qrystr);
return $result;
Of course you should use PDO:bindparam and check your variables against attack, etc
but gives the example
additional info
If you have a problem with handling NULL values, you can use following codes so that imploding names and values only for whose value is not NULL.
foreach ($result[0] as $index => $value) {
if ($value === null) unset($result[0][$index]);
}
SET #table = 'the_table';
SELECT GROUP_CONCAT(IF(COLUMN_NAME IN ('id'), 0, CONCAT("\`", COLUMN_NAME, "\`"))) FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = #table INTO #columns;
SET #s = CONCAT('INSERT INTO ', #table, ' SELECT ', #columns,' FROM ', #table, ' WHERE id=1');
PREPARE stmt FROM #s;
EXECUTE stmt;
depending on how many columns there are, you could just name the columns, sans the ID, and manually add an ID or, if it's in your table, a secondary ID (sid):
insert into PROG(date, level, Percent, sid) select date, level, Percent, 55 from PROG where sid = 31
Here, if sid 31 has more than one resultant row, all of them will be copied over to sid 55 and your auto iDs will still get auto-generated.
for ID only:
insert into PROG(date, level, Percent, ID) select date, level, Percent, 55 from PROG where ID = 31
where 55 is the next available ID in the table and ID 31 is the one you want to copy.
I am using a temporary table:
CREATE TEMPORARY TABLE tmp SELECT * FROM sitelog WHERE 1=1;
ALTER TABLE tmp DROP COLUMN `ID`;
INSERT INTO sitelog SELECT 0, tmp.* FROM tmp;
DROP TEMPORARY TABLE tmp;
INSERT into table_name (
`product_id`,
`other_products_url_id`,
`brand`,
`title`,
`price`,
`category`,
`sub_category`,
`quantity`,
`buy_now`,
`buy_now_url`,
`is_available`,
`description`,
`image_url`,
`image_type`,
`server_image_url`,
`reviews`,
`hits`,
`rating`,
`seller_name`,
`seller_desc`,
`created_on`,
`modified_on`,
`status`)
SELECT
`product_id`,
`other_products_url_id`,
`brand`,
`title`,
`price`,
`category`,
`sub_category`,
`quantity`,
`buy_now`,
concat(`buy_now_url`,'','#test123456'),
`is_available`,
`description`,
`image_url`,
`image_type`,
`server_image_url`,
`reviews`,
`hits`,
`rating`,
`seller_name`,
`seller_desc`,
`created_on`,
`modified_on`,
`status`
FROM `table_name` WHERE id='YourRowID';