obtain the ";" in liquibase output sql when using mssql - sql-server

Is there any way to control the output of the Liquibase command updateSql when running on Microsoft SQL Server, so that the resulting SQL text is terminated with the ; instead of the GO, similarly to what is done by default for PostgreSQL?
Current output for SQL Server:
CREATE TABLE T0000 ([field1] varchar(255), field2 varchar(255))
GO
ALTER TABLE T0000 ALTER COLUMN [field1] varchar(255) NOT NULL
GO
Output for PostgreSQL:
CREATE TABLE public."T0000" (field1 TEXT, field2 TEXT);
ALTER TABLE public."T0000" ALTER COLUMN field1 SET NOT NULL;
Thanks.

I had some result doing:
cat original-sql-file.sql | sed -z 's/\nGO\n/;\n/g'
but this is done as Liquibase output post-processing.
I would like to know if it is possible to obtain this "natively" with some Liquibase setting/command or whatever.

Related

SQL Server 2019 infinitely recompiles inline table valued function that does full text search with Parameterization = Forced

I have hit a problem with SQL Server that results in it infinitely recompiling a function.
To reproduce, create a new database with the option Parameterization = Forced or execute the following on an existing DB:
ALTER DATABASE [DatabaseName] SET PARAMETERIZATION FORCED WITH NO_WAIT
Then execute the following script:
CREATE TABLE dbo.TestTable(
ID int IDENTITY(1,1) NOT NULL,
FullTextField varchar(100) NULL,
CONSTRAINT PK_TestTable PRIMARY KEY CLUSTERED
(ID ASC)
)
GO
IF NOT EXISTS(SELECT 1 FROM sysfulltextcatalogs WHERE name = 'FullTextCat')
CREATE FULLTEXT CATALOG FullTextCat;
GO
CREATE FULLTEXT INDEX ON dbo.TestTable (FullTextField) KEY INDEX PK_TestTable
ON FullTextCat
WITH
CHANGE_TRACKING AUTO
GO
CREATE OR ALTER FUNCTION dbo.fn_TestFullTextSearch(#Filter VARCHAR(8000))
RETURNS TABLE
AS
RETURN SELECT
ID,
FullTextField
FROM dbo.TestTable
WHERE CONTAINS(FullTextField, #Filter)
GO
SELECT * FROM dbo.fn_TestFullTextSearch('"a*"')
The query will never return. Running SQL Profiler to monitor SP:CacheInsert and SP:CacheRemove will show SQL server is doing this endlessly and the SQL logs will show countless "A possible infinite recompile was detected for SQLHANDLE" messages.
Setting the Parameterization = Simple works around the issue but we need this to be set to Forced for other reasons.
Has anyone come across this issue before and/or have a suggested solution?
Thanks,
Chuck
While I still experience the problem with the original code I provided, by following #Martin's approach of explicitly parameterizing the call to the function:
EXEC sys.sp_executesql N'SELECT * FROM dbo.fn_TestFullTextSearch(#Filter)', N'#Filter VARCHAR(4)', #Filter = '"a*"'
I have been able to successfully work around the problem.

INSERT INTO table RETURNING trigger-generated primary key from SQL Server linked server to Oracle (11g)

Scenario: get trigger-generated primary key when calling INSERT INTO from SQL Server linked server to Oracle
Given
Oracle 11g table with columns PRIMARY_KEY_ID, FIELD1, FIELD2, CREATE_DATE. Table has "BEFORE INSERT" trigger that selects NEXTVAL from a sequence into PRIMARY_KEY_ID field.
SQL Server 2008 R2 with Linked Server to the Oracle database containing the table above.
When I insert a record into the Oracle table, then I want to retrieve the trigger-generated primary key.
How do I do this?
Make sure these properties are set on the SQL Server linked server:
RPC=True
RPC Out=True
Execute this code in SQL Server:
DECLARE #Field1 NVARCHAR(42);
DECLARE #Field2 NVARCHAR(42);
DECLARE #PrimaryKeyValue INT;
EXECUTE (
'begin INSERT INTO MYSCHEMA.MYTABLE (
FIELD1
,FIELD2
,CREATE_DATE
)
VALUES (
?
,?
,sysdate
) RETURNING PRIMARY_KEY_ID INTO :PrimaryKeyValue; end;'
,#Field1
,#Field2
,#PrimaryKeyValue OUTPUT
) at oracle_linked_server;
Notes
begin and end; are required in the statement.
The #PrimaryKeyValue variable declared in SQL Server is the same as the :PrimaryKeyValue output parameter; Oracle uses a colon prefix for parameters.
See Calling Oracle stored procedure with output parameter from SQL Server, which provided the inspiration for this answer.

How to execute sql scripts from a staging table in sql stored procedure

What are the best approaches to the below scenario?
In my C# program, I have some sql commands such as UPDATE, INSERT, DELETE. I could execute them in my C# program (which works fine) but I need to execute these sql commands when one of the stored procedure comes to the last line. So I am planning to store the sql commands in some staging table in the same database and then I would like to open this table within the stored procedure and execute one by one.
What is the best approach in terms of opening a table within stored procedure and then traversing through the table based on some condition (like select * from TempStagingTable where customerId = '1000'). If it returns 10 records, I would like to loop them and execute the sql command stored in a column named "CustomSqlScript"
PS: I am using SQL 2008 R2.
Well, you can select the data from table A initially, and instead of using cursor you can use while loop(as it will increase your performance compared to cursor) and then you can execute your predefined SQL statement from table B
Please find below sql scripts to do the same
Please note: I have not made use of any relation,This is just a plain example
CREATE TABLE test1(
customSqlScripts VARCHAR(100)
)
CREATE TABLE test2(
customer_Id INT PRIMARY KEY ,
first_Name VARCHAR(100),
last_name VARCHAR(100)
)
INSERT INTO test1 VALUES('Select first_Name from test2 where customer_Id=')
INSERT INTO test2 VALUES('1','Rohit','Tiwari')
DECLARE #Count INT
DECLARE #iCount INT=0
DECLARE #dummysql VARCHAR(100)
SELECT #Count= Count(*)
FROM test2
WHERE last_name='Tiwari'
WHILE(#icount<#count)
BEGIN
SELECT #dummysql =customSqlScripts
FROM test1
SET #dummysql=#dummysql+'1'
EXEC (#dummysql)
SET #icount=#icount+1
END

How to Exclude Data for Specific Tables

I am using mysqldump to create a canonical installation script for a MySQL database. I would like to dump the data for able half of the tables in the database, but exclude the data from the other tables. I am aware of the following two commands:
--no-data
--ignore-table
But the first applies to all tables, and I believe the second excludes the table entirely from the dump (e.g. create statements) not just the data in the table. Anyone know how to use mysqldump to achieve my goal?
EDIT:
found a near duplicate question: mysqldump entire structure but only data from selected tables in a single command
How about running two separate calls to mysqldump? One to create the database and ignore the tables you don't want data from. The other to just create the remaining tables without data. You could either run the two scripts separately, or concatenate them together to create a final script.
There is one other option to get everything done (in a single call to mysql itself) but it should probably never be attempted.
In tribute to H.P. Lovecraft, (and based upon Anuya's stored procedure to create INSERT statements) here's The Stored Procedure Which Must Not Be Called:
Note: This unholy, arcane stored procedure would only be run by a madman and is presented below purely for educational purposes.
DELIMITER $$
DROP PROCEDURE IF EXISTS `pseudoDump` $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `pseudoDump`(
in_db varchar(20),
in_tables varchar(200),
in_data_tables varchar(200)
)
BEGIN
DECLARE Whrs varchar(500);
DECLARE Sels varchar(500);
DECLARE Inserts varchar(200);
DECLARE tablename varchar(20);
DECLARE ColName varchar(20);
SELECT `information_schema`.`TABLE_NAME` INTO tablename FROM TABLES WHERE TABLE_SCHEMA = in_db AND TABLE_NAME IN ( in_tables );
tabdumploop: LOOP
SHOW CREATE TABLE tablename;
LEAVE tabdumploop;
END LOOP tabdumploop;
SELECT `information_schema`.`TABLE_NAME` INTO tablename FROM TABLES WHERE TABLE_SCHEMA = in_db ;
datdumploop: LOOP
SELECT group_concat(concat('concat(\'"\',','ifnull(',column_name,','''')',',\'"\')')) INTO #Sels from `information_schema`.`COLUMNS` where table_schema=in_db and table_name=tablename;
SELECT group_concat('`',column_name,'`') INTO #Whrs from `information_schema`.`COLUMNS` where table_schema=in_db and table_name=tablename;
SET #Inserts=concat("select concat('insert IGNORE into ", in_db,".",tablename," values(',concat_ws(',',",#Sels,"),');') as MyColumn from ", in_db,".",tablename, " where 1 group by ",#Whrs, ";");
PREPARE Inserts FROM #Inserts;
EXECUTE Inserts;
LEAVE datdumploop;
END LOOP datdumploop;
END $$
DELIMITER ;
... thankfully, I was saved from witnessing the soul-wrenching horror this procedure must surely wreak by MySQL Bug #44009 ...
mysqldump -u user -h host.example.com -p database table1 table2 table3
You might find what you need here:
http://www.electrictoolbox.com/mysqldump-selectively-dump-data/
Using where statements is probably the easiest way to achieve what you are trying to do.

mysqldump table names prefix

I have two mysql databases that have almost the same structure and representing the data of the same web app but one of them represents the current version and second one was made long time ago.
How can I create the database with both dumps inside but with old_ prefix for tables from the first and new_ prefix for tables from the second database?
Is there any mysqldump options to setup the prefix or other solution?
A "mysqldump file" is just a text file full of SQL statements, so you can make quick modifications like these in a text editor.
1) Dump the two databases individually.
2) Edit the "old" dump file:
add the correct use mydatabase; line
do a search and replace to add old_ in front of the table names.
3) Then, cat dump1 dump2 > combined_dump
4) mysql < combined_dump
This sed script is perhaps a little safer. Save it to a file and use sed -f to filter the dump file.
s/\(-- Table structure for table `\)\([^`]\+\)\(`\)/\1xyzzy_\2\3/
s/\(DROP TABLE IF EXISTS `\)\([^`]\+\)\(`\)/\1xyzzy_\2\3/
s/\(CREATE TABLE `\)\([^`]\+\)\(` (\)/\1xyzzy_\2\3/
s/\(-- Dumping data for table `\)\([^`]\+\)\(`\)/\1xyzzy_\2\3/
s/\(\/\*!40000 ALTER TABLE `\)\([^`]\+\)\(` DISABLE KEYS \*\/\)/\1xyzzy_\2\3/
s/\(LOCK TABLES `\)\([^`]\+\)\(` WRITE\)/\1xyzzy_\2\3/
s/\(INSERT INTO `\)\([^`]\+\)\(` VALUES (\)/\1xyzzy_\2\3/
s/\(\/\*!40000 ALTER TABLE `\)\([^`]\+\)\(` ENABLE KEYS \*\/\)/\1xyzzy_\2\3/
Search and replace xyzzy_ with your desired table prefix.
Restore both the databases as it is.
Use the following stored procedure to move all the tables from one DB to another DB after adding the prefix.
After moving delete the source database.
This stored procedure gets the table list from MySQL's inmemory tables in information_schema and automatically moves to another DB using the RENAME command.
DELIMITER $$
USE `db`$$
DROP PROCEDURE IF EXISTS `renameDbTables`$$
CREATE DEFINER=`db`#`%` PROCEDURE `renameDbTables`(
IN from_db VARCHAR(20),
IN to_db VARCHAR(30),
IN to_name_prefix VARCHAR(20)
)
BEGIN
/*
call db.renameDbTables('db1','db2','db_');
db1.xxx will be renamed to db2.db_xxx
*/
DECLARE from_state_table VARCHAR(20) DEFAULT '';
DECLARE done INT DEFAULT 0;
DECLARE b VARCHAR(255) DEFAULT '';
DECLARE cur1 CURSOR FOR SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA=from_db;
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
OPEN cur1;
REPEAT
FETCH cur1 INTO from_state_table;
IF NOT done THEN
-- select from_state_table;
SET #QUERY = '';
SET #QUERY = CONCAT(#QUERY,'RENAME TABLE ',from_db,'.', from_state_table,' TO ',to_db,'.', to_name_prefix, from_state_table,';');
-- SELECT #query;
PREPARE s FROM #QUERY;
EXECUTE s;
DEALLOCATE PREPARE s;
END IF;
UNTIL done END REPEAT;
CLOSE cur1;
END$$
DELIMITER ;
Import them into different databases. Say they're called newdb and olddb. Then you can copy table1 to old_table1 like:
insert into newdb.old_table1
select *
from olddb.table1
If you have a huge number of tables, generate a script to copy them:
select concat('insert into newdb.old_', table_name,
'select * from olddb.', table_name, ';')
from information_schema.tables
where table_schema = 'olddb'
I have done the following using mysqldump and sed in the past, but I'll admit it may only be effective for one table at a time.
$ mysqldump -u user --password=mypass MyDB MyTable | sed s/MyTable/old_Mytable/ | mysql -u other_user -p NewDB
You could create a shell script with a list of the commands, one for each table, or perhaps another user has a way to modify this to work against multiple tables effectively in one shot.
Peer
I may be misunderstanding the problem, but it sounds like you want to dump the 2 databases into a single SQL file to be used to restore the dbs, with the old tables going into one schema and the new tables going into another.
IF that's what you are trying to do, the simplest approach is just to insert the proper "use database" command before each dump.
Like so:
echo "use old_db;" > /tmp/combined_dump.sql
mysqldump old_db >> /tmp/combined_dump.sql
echo "use new_db;" >> /tmp/combined_dump.sql
mysqldump new_db >> /tmp/combined_dump.sql
Run the following query:
SELECT Concat('ALTER TABLE ', TABLE_NAME, ' RENAME TO my_prefix_', TABLE_NAME, ';') FROM information_schema.tables WHERE table_schema = 'my_database'
The output of which is several queries. Then run those queries.
This won't work if there's constraints, or other complicated things, but for simple DBs this works fine.

Resources