SQL Query Replace All - sql

I want to modify the following query:
UPDATE wp_posts
SET post_content =
REPLACE(post_content, 'http://oldlink.com', 'http://newlink.com');
To be something that goes through all tables, columns and values. Something similar to this (but this doesn't work):
UPDATE * SET *= REPLACE(*, 'http://oldlink.com', 'http://newlink.com');
I want to replace every instance of my old link to my new link in my database. Is there any way to do this?
UPDATE
Sorry, I forgot to mention, it's MySQL. I'm currently going through all the answers and I'll be back and let you know what worked. Thanks everyone!
UPDATE 2
Hi guys (and girls), I decided to just dump the database and do manual search and replace (with TextWrangler). As this isn't (currently) a large DB, it's probably the easiest way.

Here is one that works on SQL Server -- does something like this work for you?
Search and Replace SQL Server data in all columns, of all tables
Here's a stored procedure named, SearchAndReplace, that searches
through all the character columns of all tables in the current
database, and replaces the given string with another user provided
string.

This mssql script will whine a bit if there is a computed column in a table, but it will still execute:
DECLARE #searchvalue varchar(100)
DECLARE #newvalue varchar(100)
SET nocount off
SET #searchvalue = 'http://oldlink.com'
SET #newvalue = 'http://newlink.com'
SELECT * into #t FROM
(
SELECT 'update [' + a.TABLE_name + '] SET ['+ column_name+ ']=''' + #newvalue + '''
where [' +a.column_name+
']='''+#searchvalue +'''' sqlstring
FROM INFORMATION_SCHEMA.COLUMNS a
join
INFORMATION_SCHEMA.TABLES b
ON a.TABLE_name = b.TABLE_name
and b.TABLE_type = 'base table'
WHERE data_type in ('varchar', 'char', 'nvarchar')
and character_maximum_length >= len(#newvalue)
) a
DECLARE #sqlstring as nvarchar(500)
DECLARE SqlCursor CURSOR FAST_FORWARD FOR
SELECT sqlstring FROM #t
OPEN SqlCursor
FETCH NEXT FROM SqlCursor
INTO #sqlstring
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC(#sqlstring)
FETCH NEXT FROM SqlCursor
INTO #sqlstring
END
CLOSE SqlCursor
DEALLOCATE SqlCursor
DROP TABLE #t

You didn't mention the database. I currently use Sybase ASA, where you cannot do this literally but it can be done by checking the column names from a join of systable and syscolumn and then using execute immediate

Related

SSIS Multiple Unknow Column Updates

I wonder if anyone has come across a similar situation before that could point me in the right direction..? I'll add that it's a bit frustrating as someone has replaced the NULL value with a text string containing the word 'NULL' - which I need to remove.
I have 6 quite large tables, over 250+ columns and in excess of 1 million records in each and I need to update the columns where the word NULL appears in a row and replace it with a proper NULL value - the problem is that I have no idea in which column this appears.
As a start, I've got some code that will list every column with a count of the values and anything that looks to have a lower count than expected, I'll run a SQL query to ascertain if the column contains the string 'NULL' and using the following code, replace it with NULL.
declare #tablename sysname
declare #ColName nvarchar(500)
declare #sql nvarchar(1000)
declare #sqlUpdate nvarchar(1000)
declare #ParmDefinition nvarchar(1000)
set #tablename = N'Table_Name'
Set #ColName = N'Column_Name'
set #ParmDefinition = N'#ColName nvarchar OUTPUT';
set #sql= 'Select ' + #ColName + ', Count(' + #ColName + ') from ' + #tablename + ' group by ' + #ColName + ''
Set #sqlUpdate = 'Update ' + #tablename + ' SET ' + #ColName + ' = NULL WHERE '+ #ColName + ' = ''NULL'''
print #sql
print #sqlUpdate
EXECUTE sp_executesql #sql, #ParmDefinition, #ColName=#ColName OUTPUT;
EXECUTE sp_executesql #sqlUpdate, #ParmDefinition, #ColName=#ColName OUTPUT;
What I'm trying to with SSIS is to iterate through each column,
Select Column_Name from Table_Name where Column_Name = 'NULL'
run the appropriate query, and perform the update.
So far I can extract the column names from Information.Schema and get a record count from the appropriate table, but when it comes to running the actual UPDATE statement (as above, sqlUpdate) - there doesn't seem to be a component that's happy with the dynamic phrasing of the query.
I'm using a Conditional Split to determine where to go if there are records (which may be incorrect) and I've tried OLE DB Command for the update.
In short, I'm wondering whether SSIS is the best tool for this job or whether I'm looking in the wrong place!
I'm using SSIS 2005, which may well have limitations that I'm not yet aware of!
Any guidance would be appreciated.
Thanks,
Jon
The principle is basically sound, but I would leave SSIS out, and do it with SSMS directly against the SQL Server and build the looping logic there, probably with a cursor.
I'm not sure whether you need to check the count of potential values first - you might just as well apply the update and accept that sometimes it will update no rows - the filtering will then not be duplicated.
Something like
declare columns cursor local read_only for
select
c.TABLE_CATALOG,
c.TABLE_SCHEMA,
c.TABLE_NAME,
c.COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS c
inner join INFORMATION_SCHEMA.TABLES t
on c.TABLE_CATALOG = t.TABLE_CATALOG
and c.TABLE_SCHEMA = t.TABLE_SCHEMA
and c.TABLE_NAME = c.TABLE_NAME
where c.DATA_TYPE like '%varchar%'
open columns
declare #catalog varchar(100), #schema varchar(100), #table varchar(100), #column varchar(100)
fetch from columns into #catalog, #schema, #table, #column
while ##FETCH_STATUS= 0
begin
-- construct update here and execute it.
select #catalog, #schema, #table, #column
fetch next from columns into #catalog, #schema, #table, #column
end
close columns
deallocate columns
You might also consider applying all the updates to the table in one hit, removing the filter and using nullif dependent on the density of the bad data.
eg:
update table
set
col1 = nullif(col1, 'null'),
col2 = nullif(col2, 'null'),
...
SSIS won't be the best option for you. Conceptually, you are performing updates, lots of updates. SSIS can do really fast inserts. Updates, are fired off on a row by agonizing row basis.
In a SQL based approach, you'd be firing off 1000 update statements to fix everything. In an SSIS based scenario, using a data flow with OLE DB Command, you're looking at 1000 * 1000000.
I would skip the cursor myself. It is an acceptable time to use a cursor but if your tables are as littered with 'NULL' as it sounds, just assume you're updating every row and fix all the fields in a given record instead of coming back to the same row for each thing needing fixed.

Dynamically search columns for given table

I need to create a search for a java app I'm building where users can search through a SQL database based on the table they're currently viewing and a search term they provide. At first I was going to do something simple like this:
SELECT * FROM <table name> WHERE CAST((SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<table name>')
AS VARCHAR) LIKE '%<search term>%'
but that subquery returns more than one result, so then I tried to make a procedure to loop through all the columns in a given table and put any relevant fields in a results table, like this:
CREATE PROC sp_search
#tblname VARCHAR(4000),
#term VARCHAR(4000)
AS
SET nocount on
SELECT COLUMN_NAME
INTO #tempcolumns
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #tblname
ALTER TABLE #tempcolumns
ADD printed BIT,
num SMALLINT IDENTITY
UPDATE #tempcolumns
SET printed = 0
DECLARE #colname VARCHAR(4000),
#num SMALLINT
WHILE EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0)
BEGIN
SELECT #num = MIN(num)
FROM #tempcolumns
WHERE printed = 0
SELECT #colname = COLUMN_NAME
FROM #tempcolumns
WHERE num = #num
SELECT * INTO #results FROM #tblname WHERE CAST(#colname AS VARCHAR)
LIKE '%' + #term + '%' --this is where I'm having trouble
UPDATE #tempcolumns
SET printed = 1
WHERE #num = num
END
SELECT * FROM #results
GO
This has two problems: first is that it gets stuck in an infinite loop somehow, and second I can't select anything from #tblname. I tried using dynamic sql as well, but I don't know how to get results from that or if that's even possible.
This is for an assignment I'm doing at college and I've gotten this far after hours of trying to figure it out. Is there any way to do what I want to do?
You need to only search columns that actually contain strings, not all columns in a table (which may include integers, dates, GUIDs, etc).
You shouldn't need a #temp table (and certainly not a ##temp table) at all.
You need to use dynamic SQL (though I'm not sure if this has been part of your curriculum so far).
I find it beneficial to follow a few simple conventions, all of which you've violated:
use PROCEDURE not PROC - it's not a "prock," it's a "stored procedure."
use dbo. (or alternate schema) prefix when referencing any object.
wrap your procedure body in BEGIN/END.
use vowels liberally. Are you saving that many keystrokes, never mind time, saying #tblname instead of #tablename or #table_name? I'm not fighting for a specific convention but saving characters at the cost of readability lost its charm in the 70s.
don't use the sp_ prefix for stored procedures - this prefix has special meaning in SQL Server. Name the procedure for what it does. It doesn't need a prefix, just like we know they're tables even without a tbl prefix. If you really need a prefix there, use another one like usp_ or proc_ but I personally don't feel that prefix gives you any information you don't already have.
since tables are stored using Unicode (and some of your columns might be too), your parameters should be NVARCHAR, not VARCHAR. And identifiers are capped at 128 characters, so there is no reason to support > 257 characters for #tablename.
terminate statements with semi-colons.
use the catalog views instead of INFORMATION_SCHEMA - though the latter is what your professor may have taught and might expect.
CREATE PROCEDURE dbo.SearchTable
#tablename NVARCHAR(257),
#term NVARCHAR(4000)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT * FROM ' + #tablename + ' WHERE 1 = 0';
SELECT #sql = #sql + '
OR ' + c.name + ' LIKE ''%' + REPLACE(#term, '''', '''''') + '%'''
FROM
sys.all_columns AS c
INNER JOIN
sys.types AS t
ON c.system_type_id = t.system_type_id
AND c.user_type_id = t.user_type_id
WHERE
c.[object_id] = OBJECT_ID(#tablename)
AND t.name IN (N'sysname', N'char', N'nchar',
N'varchar', N'nvarchar', N'text', N'ntext');
PRINT #sql;
-- EXEC sp_executesql #sql;
END
GO
When you're happy that it's outputting the SELECT query you're after, comment out the PRINT and uncomment the EXEC.
You get into an infinite loop because EXISTS(SELECT MIN(num) FROM #tempcolumns WHERE printed = 0) will always return a row even if there are no matches - you need to EXISTS (SELECT * .... instead
To use dynamic SQL, you need to build up a string (varchar) of the SQL statement you want to run, then you call it with EXEC
eg:
declare #s varchar(max)
select #s = 'SELECT * FROM mytable '
Exec (#s)

Delete all tables with a certain prefix name in a SQL 2008 database programmatically

I have 3000+ tables in my SQL 2008 database with names like listed below, that all starts with tempBinary_, that I need to delete programmatically, how do I do that?
I don't know if I prefer the solution in a SQL-script or with use of LINQtoSQL, i guess both are fine.
tempBinary_002c90322f4e492795a0b8a14e2f7c99
tempBinary_0039f7db05a9456f96eb3cd6a788225a
tempBinary_0057da9ef0d84017b3d0bbcbfb934fb2
I've used Like before on columns, but I don't know if it good for table names too.
Maybe something like this, where LIKE is used, can do it? I don't know.
Use [dbo].[database_name]
DROP TABLE table_name
WHERE table_name LIKE 'tempBinary_%'
Any ideas?
declare #stmt varchar(max) = ''
declare #tbl_name varchar(255)
DECLARE tbl_cursor CURSOR FORWARD_ONLY READ_ONLY
FOR select name
from sysobjects
where xtype='u' and name like 'tempBinary%'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor
INTO #tbl_name;
WHILE ##FETCH_STATUS = 0
BEGIN
set #stmt = #stmt + 'drop table ' + #tbl_name + ';' + CHAR(13)
FETCH NEXT FROM tbl_cursor
INTO #tbl_name
end
CLOSE tbl_cursor;
DEALLOCATE tbl_cursor;
execute sp_sqlexec #stmt

In SQL Server 2008, how should I copy data from database to another database?

I'm trying to write a stored procedure to copy a subset of data from one set of tables to an identical set of tables in a different database. The "source" database needs to be a parameter to the stored procedure.
I've struggled with this for two days now, and I thought I had a good solution:
Validate that the schemas are the same.
Create temporary "rmt" synonyms for the source tables using dynamic SQL.
Copy the data using INSERT INTO A SELECT * FROM rmtA WHERE <criteria>
Delete the synonyms.
This works pretty well for most tables, but for tables that contain an identity column, I'm forced not only to SET IDENTITY_INSERT ON & OFF, but even worse, I can't use SELECT *; I have to specify all the columns explicitly. This will be a nightmare if I add or delete columns later.
I've gotta get something out the door, so I'm going with this solution for now, but I'd like to think that there's a better solution out there somewhere.
Help?
It sounds like you're using dynamic SQL in your stored procedure, so you're ready to dynamically create your list of columns in the SELECT clause.
You can select from sys.columns to get the list of columns, and learn if the table has an identity column. Here's a query that shows the information you need to create the list of columns.
SELECT c.name, is_identity
FORM sys.columns c
WHERE object_id = object_id('MyTable')
In short, if is_identity is 1 for at least one column, you'll need to include the SET IDENTITY_INSERT. And, you would exclude any columns from the SELECT clause where is_identity = 1.
And, this approach will adapt to new columns you add to the tables.
Here's an example
DECLARE #TableName varchar(128) = 'MyTableName'
DECLARE #ColumnName varchar(128)
DECLARE #IsIdentity bit
DECLARE #TableHasIdentity bit = 0
DECLARE #sql varchar(2000) = 'SELECT '
-- create cursor to step through list of columns
DECLARE MyCurs CURSOR FOR
SELECT c.name, is_identity
FROM sys.columns c
WHERE object_id = object_id(#TableName)
ORDER BY column_id
-- open cursor and get first row
OPEN MyCurs
FETCH NEXT FROM MyCurs INTO #ColumnName, #IsIdentity
-- process each column in the table
WHILE ##FETCH_STATUS = 0
BEGIN
IF #IsIdentity = 0
-- add column to the SELECT clause
SET #sql = #sql + #ColumnName + ', '
ELSE
-- indicate that table has identity column
SET #TableHasIdentity = 1
-- get next column
FETCH NEXT FROM MyCurs INTO #ColumnName, #IsIdentity
END
-- cursor cleanup
CLOSE MyCurs
DEALLOCATE MyCurs
-- add FROM clause
SET #sql = LEFT(#sql, LEN(#sql)-1) + CHAR(13) + CHAR(10) + 'FROM ' + #TableName
-- add SET IDENTITY if necessary
IF #TableHasIdentity = 1
SET #sql = 'SET IDENTITY_INSERT ' + #TableName + ' ON' + CHAR(13) + CHAR (10)
+ #sql + CHAR(13) + CHAR (10)
+ 'SET IDENTITY_INSERT ' + #TableName + ' OFF'
PRINT #sql

Delete all table data in a set [DB].[audit].[tables]

So, I have a database with around 100 audit tables and I want to empty them out preferably in 1 sql query. The database has 2 sets of tables [audit] and [dbo]. I'm not even sure what I should be calling these groups of tables so finding any kind of results from google is proving difficult.
Any suggestions?
You can find all tables with a certain schema name like:
select name from sys.tables where schema_name(schema_id) = 'audit'
With a cursor, you iterate over those tables, and empty them using TRUNCATE TABLE:
use db
declare #query nvarchar(max)
declare #tablename nvarchar(max)
declare #curs cursor
set #curs = cursor for select name from sys.tables
where schema_name(schema_id) = 'audit'
open #curs
fetch next from #curs into #tablename
while ##FETCH_STATUS = 0
begin
set #query = N'truncate table audit.' + #tablename
exec sp_executesql #query
fetch next from #curs into #tablename
end
close #curs
deallocate #curs
If you want to delete the tables instead, use:
set #query = N'drop table audit.' + #tablename
You could also use the sp_msforeachtable stored procedure.
It lets you perform a query on each user table in the current DB.
For example the following will truncate all user tables in your DB
Use YourDB
Exec sp_msforeachtable 'TRUNCATE TABLE ?'
And this will truncate all user tables in the specified db that belong to the audit schema.
Use YourDB
Exec sp_msforeachtable #command1 = '
if (Select Object_Schema_name(object_id(''?''))) = ''dbo''
Begin
TRUNCATE TABLE ?
print ''truncated '' + ''?''
End
'
Also Here is a blog entry with some more uses for this stored procedure.