I’m using MySQL for C++ and I want to create a new table for all the tables in my second database. The code I have now is:
CREATE TABLE new_table LIKE original_table;
INSERT INTO new_table SELECT * FROM original_table;
I want to this to work like a loop where all the tables and data in those tables are created for every table and piece of data there is in my second database. Can someone help me?
We can use a stored procedure to do the job in a loop. I just wrote the code and tested it in workbench. Got all my tables(excluding view) from sakila database to my sakila_copy database:
use testdb;
delimiter //
drop procedure if exists copy_tables //
create procedure copy_tables(old_db varchar(20),new_db varchar(20))
begin
declare tb_name varchar(30);
declare fin bool default false;
declare c cursor for select table_name from information_schema.tables where table_schema=old_db and table_type='BASE TABLE';
declare continue handler for not found set fin=true;
open c;
lp:loop
fetch c into tb_name;
if fin=true then
leave lp;
end if;
set #create_stmt=concat('create table ',new_db,'.',tb_name,' like ',old_db,'.',tb_name,';') ;
prepare ddl from #create_stmt;
execute ddl;
deallocate prepare ddl;
set #insert_stmt=concat('insert into ',new_db,'.',tb_name,' select * from ',old_db,'.',tb_name,';');
prepare dml from #insert_stmt;
execute dml;
deallocate prepare dml;
end loop lp;
close c;
end//
delimiter ;
create database sakila_copy;
call testdb.copy_tables('sakila','sakila_copy');
-- after the call, check the tables in sakila_copy to find the new tables
show tables in sakila_copy;
Note: As I stated before, only base tables are copied. I deliberately skipped views, as they provide logical access to tables and hold no data themselves.
Related
This question already has answers here:
Return deleted rows in sqlite
(3 answers)
Closed 3 years ago.
I want to delete several rows from a table by using DELETE LIKE query in C++. I know how to do it and it works. But also I want to know which rows were actually deleted. Is there a way to do it via 1 query or it is impossible and the only way to do it is
1. SELECT LIKE
2. DELETE LIKE
As alternative to SELECT -> DELETE you could also use a TRIGGER.
The following example shows/demonstrates a relatively generic way (a little inefficient as such) for both :-
DROP TABLE IF EXISTS mytable;
DROP TABLE IF EXISTS mytable_deletions;
DROP TABLE IF EXISTS mytable_deletions2;
DROP TRIGGER IF EXISTS mytable_deletions_trigger;
/* MAIN TABLE */
CREATE TABLE IF NOT EXISTS mytable(id INTEGER PRIMARY KEY, mydata TEXT);
/* CREATE TABLES TO RECORD DELETIONS (first for 1. select->delete the other for 2. trigger)*/
/* Note that these are created based upon the source table, with an additional column srowid so as to be able to definitively delete rows (extra column may not be needed) */
CREATE /*TEMP option? */ TABLE IF NOT EXISTS mytable_deletions AS SELECT 0 AS srowid,* FROM mytable WHERE mydata <> mydata;
CREATE /*TEMP option? */ TABLE IF NOT EXISTS mytable_deletions2 AS SELECT 0 AS srowid,* FROM mytable WHERE mydata <> mydata;
/* Create the BEFORE DELETE Trigger */
CREATE TRIGGER IF NOT EXISTS mytable_deletions_trigger BEFORE DELETE ON mytable
BEGIN
INSERT INTO mytable_deletions2 SELECT rowid AS srowid,* FROM mytable WHERE rowid = old.rowid;
END
;
/* LOAD TESTING DATA */
INSERT INTO mytable (mydata) VALUES('A'),('B'),('C'),('D'),('E');
/* CLEAR PREVIOUS DELETIONS */
DELETE FROM mytable_deletions;
DELETE FROM mytable_deletions2;
/* 1. RECORD DELETIONS PRIOR AND DELETE ACCORDING TO RECORDED DELETIONS */
INSERT INTO mytable_deletions SELECT rowid AS srowid,* FROM mytable WHERE mydata >= 'C';
/* DO THE ACTUAL DELETIONS (will fire trigger 2.) */
DELETE FROM mytable WHERE rowid IN (SELECT srowid FROM mytable_deletions);
/* Display results from TRIGGER */
SELECT * FROM mytable;
SELECT * FROM mytable_deletions;
SELECT * FROM mytable_deletions2;
/* CLEANUP */
DROP TABLE IF EXISTS mytable;
DROP TABLE IF EXISTS mytable_deletions;
DROP TABLE IF EXISTS mytable_deletions2;
DROP TRIGGER IF EXISTS mytable_deletions_trigger;
Running the above results in :-
Remaining data :-
Deleted Rows (select->delete)
Deleted Rows (trigger)
I generate a list of ID numbers. I want to execute an insert statement that grabs all records from one table where the ID value is in my list and insert those records into another table.
Instead of running through multiple execute statements (as I know is possible), I found this cx_Oracle function, that supposedly can execute everything with a single statement and list parameter. (It also avoids the clunky formatting of the SQL statement before passing in the parameters) But I think I need to alter my list before passing it in as a parameter. Just not sure how.
I referenced this web page:
https://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlcursor-executemany.html
ids = getIDs()
print(ids)
[('12345',),('24567',),('78945',),('65423',)]
sql = """insert into scheme.newtable
select id, data1, data2, data3
from scheme.oldtable
where id in (%s)"""
cursor.prepare(sql)
cursor.executemany(None, ids)
I expected the SQL statement to execute as follows:
Insert into scheme.newtable
select id, data1, data2, data3 from scheme.oldtable where id in ('12345','24567','78945','65423')
Instead I get the following error:
ORA-01036: illegal variable name/number
Edit:
I found this StackOverflow: How can I do a batch insert into an Oracle database using Python?
I updated my code to prepare the statement before hand and updated the list items to tuples and I'm still getting the same error.
You use executemany() for batch DML, e.g. when you want to insert a large number of values into a table as an efficient equivalent of running multiple insert statements. There are cx_Oracle examples discussed in https://blogs.oracle.com/opal/efficient-and-scalable-batch-statement-execution-in-python-cx_oracle
However what you are doing with
insert into scheme.newtable
select id, data1, data2, data3
from scheme.oldtable
where id in (%s)
is a different thing - you are trying to execute one INSERT statement using multiple values in an IN clause. You would use a normal execute() for this.
Since Oracle keeps bind data distinct from SQL, you can't pass in multiple values to a single bind parameter because the data is treated as a single SQL entity, not a list of values. You could use %s string substitution syntax you have, but this is open to SQL Injection attacks.
There are various generic techniques that are common to Oracle language interfaces, see https://oracle.github.io/node-oracledb/doc/api.html#sqlwherein for solutions that you can rewrite to Python syntax.
using temporary table to save ids (batch insert)
cursor.prepare('insert into temp_table values (:1)')
dictList = [{'1': x} for x in ids]
cursor.executemany(None, dictList)
then insert selected value into newtable
sql="insert into scheme.newtable (selectid, data1, data2, data3 from scheme.oldtable inner join temp_table on scheme.oldtable.id = temp_table.id)"
cursor.execut(sql,connection)
the script of create temporary table in oracle
CREATE GLOBAL TEMPORARY TABLE temp_table
(
ID number
);
commit
I hope this useful.
I have the following tables:- evaluations, evaluation_options and options. I am trying to create an evaluation and evaluation_option on one page.
To create the evaluation_option I will need evaluation_id after an evaluation is created. I am getting the option_id from a List of Value.
At this point, I am not sure how to get this done as I am new to PL-SQL & SQL.
For this, I did a dynamic query to create both tables. I don't think this is the best way of getting the job done, I am open up to resolve this in the right way.
This is my code:-
DECLARE
row_id evaluations.id%TYPE;
BEGIN
INSERT INTO EVALUATIONS (class_student_rotations_id, strengths,
suggestions) VALUES (:P12_CLASS_STUDENT_ROTATIONS_ID, :P12_STRENGTHS,
:P12_SUGGESTIONS);
SELECT id into row_id FROM EVALUATIONS WHERE ROWID=(select max(rowid)
from EVALUATIONS);
INSERT ALL
INTO evaluation_options (option_id, evaluation_id) VALUES
(:P12_APPLICATION_OF_BASICS, row_id)
SELECT * FROM DUAL;
END;
I have a large target table with columns (id, value). I want to update value='old' to value='new'.
The simplest way would be to UPDATE target SET value='new' WHERE value='old';
However, this deletes and creates new rows and is not recommended, possibly. So I tried to do a merge column update:
# staging
CREATE TABLE stage (LIKE target INCLUDING DEFAULTS);
INSERT INTO stage (SELECT id, value FROM target WHERE value=`old`);
UPDATE stage SET value='new' WHERE value='old'; # ??? how do you update value?
# merge
begin transaction;
UPDATE target
SET value = stage.value FROM stage
WHERE target.id = stage.id and target.distkey = stage.distkey; # collocated join?
end transaction;
DROP TABLE stage;
This can't be the best way of creating the table stage: I have to do all these UPDATE delete/writes when I update this way. Is there a way to do it in the INSERT?
Is it necessary to force the collocated join when I use CREATE TABLE LIKE?
Are you updating all the rows in the table?
If yes you can use CTAS (create table as) which is recommended method
Assuming you table looks like this
table1
id, col1,col2, value
You can use the following SQL to create a new table
CREATE TABLE tmp_table AS
SELECT id, col1,col2, 'new_value'
FROM table1;
After you verify data in tmp_table
DROP TABLE table1;
ALTER TABLE tmp_table RENAME TO table1;
If you are not updating all the rows you can use a filter to do a CTAS and insert the rest of the rows to the new table, let me know if you need more info if this is the case
CREATE TABLE tmp_table AS
SELECT id, col1,col2, 'new_value'
FROM table1
WHERE value = 'old'
INSERT INTO tmp_table SELECT * from table1;
Next step would be DROP the tmp table and rename table1
Update: Based on your comment you can do the following, let me know if this solves your case.
This method basically creates a new table to replace your existing table.
I have used some of your code
CREATE TABLE stage (LIKE target INCLUDING DEFAULTS);
INSERT INTO stage SELECT id, 'new' FROM target WHERE value=`old`;
Above INSERT inserts rows to be updated with 'new', no need to run an UPDATE after this.
Bring unchanged rows
INSERT INTO stage SELECT id, value FROM target WHERE value!=`old`;
After this point you have target table which is your original table intact
stage table will have both sets of rows, updated rows with 'new' value and rows you did not want to change
To replace your target with stage
DROP TABLE target;
or to keep it further verification
ALTER TABLE target RENAME TO target_old;
ALTER TABLE stage RENAME TO target;
From a redshift developer:
This case doesn't require an upsert, or update+insert, and it is fine to just run the update:
UPDATE target SET value='new' WHERE value='old';
Another way would be to INSERT the rows you need and DELETE the other rows, but that's unnecessarily complicated.
I need to insert a blob in o oracle database. I am using c++ and ODBC library.
I am stucked at the insert query and update query .It is abstract for me how to make an blob insert query.
I know how to make an query for a non blob column.
My table structure is :
REATE TABLE t_testblob (
filename VARCHAR2(30) DEFAULT NULL NULL,
apkdata BLOB NULL
)
I found an exemple on insert and update :
INSERT INTO table_name VALUES (memberlist,?,memberlist)
UPDATE table_name SET ImageFieldName = ? WHERE ID=yourId
But these structure of querys or abstract to me . What should memberlist be ? why is there "?" where are the values to be inserted ?
Those question marks means that it is PreparedStatement. Such statements are good for both server and client. Server has less work because it is easier to parse such statement, and client do not need to worry about SQLInjection. Client prepares such query, builds buffer for input values and calls it.
Also such statement is executed very quick compared to "normal" queries, especially in loops, importing data from csv file etc.
I don't know what ODBC C++ library you use while ODBC is strictly C library. Other languages like Java or Python can use it too. I think the easiest is example in Python:
cursor = connection.cursor()
for txt in ('a', 'b', 'c'):
cursor.execute('SELECT * FROM test WHERE txt=?', (txt,))
Of course such PreparedStatement can be used in INSERT or UPDATE statements too, and for your example it can look like:
cursor.execute("INSERT INTO t_testblob (filename, apkdata) VALUE (?, ?)", filename, my_binary_data)