Searching for text over multiple columns? - sql

Our company is using SQL Server 2008 to manage the website's database. We have currently had a name change and so I need to change all occurrences of our old company name.
The database has multiple Tables and A LOT of columns under each table, I am only interested in finding and updating the text from all columns in one table.
Essentially what I need to be able to do is; find the string "CSQTC" over all columns in a table named "Practices", note that some columns may not contain strings, and some values in the columns may be null.
I think I know how to search for text over multiple columns, but it is a lot of code and I am sure there is a better way. This is how I think I do it
WHERE columnName LIKE '%CSQTC%'
AND columnName2 LIKE '%CSQTC%'
AND columnName3 LIKE '%CSQTC%'
AND ....
Surely there is a better way?
Thanks heaps!
EDIT: I forgot to ask how I can replace each occurence of 'CSQTC' to be 'GPTQ' instead? Thanks again

You could probably write a stored procedure that would
look for all columns containing text in your table (I don't know sql server especially, but with MySQL you'd look in the information_schema)
for each matching column, do an update request to replace the string you want.
And then obviously call that procedure (and maybe discard it unless you think you'll need it later on).
For the replacement part, it will be a simple use of REPLACE(columnName, 'CSQTC', 'GPTQ') (see REPLACE documentation at Microsoft's Technet)
P.S. see SQL server query to get the list of columns in a table along with Data types, NOT NULL, and PRIMARY KEY constraints for how to get columns of a table, and SQL Server stored procedure beginner's guide [closed] for stored procedures on sql server.

You can start with this:
SELECT c.name ,
t.name
FROM sysobjects o
INNER JOIN syscolumns c ON c.id = o.id
INNER JOIN systypes t ON t.xusertype = c.xusertype
WHERE o.name = 'YourTableName'
AND t.name IN ( 'varchar', 'nvarchar', 'text', 'ntext', 'char', 'nchar' )
To get all the columns that have text from the table.
Also you can do this:
SELECT 'Update ' + QUOTENAME(o.name) + ' Set ' + c.name + ' = Replace(' + QUOTENAME(c.name) + ', ''CSQTC'', ''GPTQ'')'
+ ' Where ' + QUOTENAME(c.name) + ' LIKE ''%CSQTC%'''
FROM sysobjects o
INNER JOIN syscolumns c ON c.id = o.id
INNER JOIN systypes t ON t.xusertype = c.xusertype
WHERE o.name = 'YourTableName'
AND t.name IN ( 'varchar', 'nvarchar', 'text', 'ntext', 'char', 'nchar' )
To get the Update instructions for each column of the table.

Related

How can I query a database of tables for a specific row value?

I'm working with a database with ~20 tables, and need to find the table which has a string value 'fees' in it.
How would I go about searching for the table which contains this?
I tried using
Select t.name as table_name, c.name as column_name
from sys.columns c
inner join sys.tables t
on c.object_id=t.object_id
Where c.name like '%fees%'
although, obviously, this only returned tables with their respective columns that contained the word 'fees'.
Is there a way to find the table containing row values = 'fees' ?
SQL databases store structured data and therefore one needs to look in the right place in the structure for data sought after. That said, you can try multiple approaches depending on the total amount of data you have.
If the amount of data is relatively small, say a few hundred megabytes up to a gigabyte or so, you can dump each table into a file in text form. Then you can use a tool like grep to search for the files containing that data.
If the amount of data is considerably larger, you can query the system catalog as you did but the form of the queries can be ones that return sql selects as output. You can then execute those sql selects to see if any of them return what you are looking for. E.g.
select
'select ' + c.name + ' from ' + t.name + ' where ' + c.name + ' like ''%fees%'''
from
sys.columns as c
inner join
sys.tables as t
on c.object_id=t.object_id
where
c.system_type_id in (167, 231) -- Get the rest of these values by inspecting sys.types
and t.type_desc = 'USER_TABLE'

How to list all tables which references a certain row of another table in SQL Server?

I'm currently working with a project that needs to clear some unused fields and normalize tables on its database in order to make it look better.
One of these tables has a field that is not a foreign key (but it should), so I can't use sp_help in order to know what tables are related.
My current task is to delete the rows with IdTipoEspecialidad = 3 only if there isn't any table that uses this rows (because I need to delete both).
Is there some shortcut or query that makes this task easier?
Assuming all these non-foreign-keyed columns at least follow some naming convention, you can execute the following query:
SELECT
'SELECT * FROM [' + schemas.name + '].[' + tables.name + ']'
+ ' WHERE [' + columns.name + '] = 3'
FROM
sys.schemas
INNER JOIN sys.tables
ON schemas.schema_id = tables.schema_id
INNER JOIN sys.columns
ON tables.object_id = columns.object_id
WHERE
columns.name LIKE '%IdTipoEspecialidad%'
The output of that query will give you a bunch of other queries, which you can run to see if there is any column referencing that specific row.

Read data from tables returned from inner query

So, I am working on a project where I need to find all tables that have the column xyz, and then remove all rows from such tables if the updated_at date for that row from that table is older than some duration.
I got the list of all tables from SQL Server like this:
SELECT
t.name AS table_name
FROM
sys.tables AS t
INNER JOIN
sys.columns c ON t.object_id = c.object_id
WHERE
c.name = 'xyz';
Now I want to use each of the tables returned from this query to DELETE all rows from these tables which satisfy some criteria. Can someone help me with the 'Nested query' please?
What you're contemplating isn't going to work; you need to explicitly specify which table you are deleting from in a delete statement.
My approach would be to use your query to dynamically generate the delete statements, then save the output of your query in a file, and run the file. This also gives you a chance to review and double-check the deletes before you run them, which is a good idea when you're making large-scale data changes like these.
select
'delete from ' + t.name + ' where updated_at <= ''2013-01-01'';'
from
sys.tables t
where
exists (select null from sys.columns c where c.object_id = t.object_id and c.name = 'xyz')
http://sqlfiddle.com/#!3/475c0/2

How can you identify the PK columns in a View

I used to use 'GetSchemaTable' to read schema information, but it was missing some 'stuff', so I wrote a big query, referencing, among other columns, sys.columns,sys.index_columns, and sys.indexes (and other tables) to return the same information I used to get from GetSchemaTable and also return the other pieces of information I want.
Problem is that GetSchemaTable will tell me if a column returned from a view is a Key column from the underlying tables but my new query does not. It'll give me the right answer all day long for tables, but not for views.
Does anyone have a solution to this? I'd hate to have to go back to GetSchemaTable just for that one bit of information, when I'm examing a view. (Plus, I really just want a SQL based solution, ideally.)
Thanks!
Unfortunately in SQL Server 2005 this is not very easy. I have played with this a bit, and it is very close, but it relies on the fact that you name your columns in your view exactly the same as they are named in the base table. This is because the now-deprecated-in-SQL-Server-2008 view sys.sql_dependencies does not properly store the referencing column_id, so there is no way to match this up with the actual columns in the view. I think SQL Server 2008 will have better options for you as they have yet again introduced a new set of dependency objects. I also didn't chase down any paths with INFORMATION_SCHEMA.KEY_COLUMN_USAGE but since these views rely solely on names and not id's of any kind you are likely in the same pickle there. So maybe this can be a start for you but like I said this will only cover the simple cases. If you alias your columns you will be out of luck. Maybe someone else with some insight into the intricacies of how these things are referenced will pull a rabbit out and figure out how to reference mismatched columns...
-- very simple; one-column key:
CREATE TABLE dbo.boo
(
far INT PRIMARY KEY
);
GO
CREATE VIEW dbo.view_boo
AS
SELECT far FROM dbo.boo;
GO
-- slightly more complex. Two-column key,
-- not all columns are in key, view columns
-- are in different order:
CREATE TABLE dbo.foo
(
splunge INT,
a INT,
mort INT,
PRIMARY KEY(splunge, mort)
);
GO
CREATE VIEW dbo.view_foo
AS
SELECT
splunge,
mort,
a
FROM
dbo.foo;
GO
SELECT
QUOTENAME(OBJECT_SCHEMA_NAME(v.[object_id])) + '.'
+ QUOTENAME(v.name) + '.' + QUOTENAME(vc.name)
+ ' references '
+ QUOTENAME(OBJECT_SCHEMA_NAME(t.[object_id]))
+ '.' + QUOTENAME(t.name) + '.' + QUOTENAME(tc.name)
FROM
sys.views AS v
INNER JOIN
sys.sql_dependencies AS d
ON v.[object_id] = d.[object_id]
INNER JOIN
sys.tables AS t
ON d.referenced_major_id = t.[object_id]
INNER JOIN
sys.columns AS tc
ON tc.[object_id] = t.[object_id]
INNER JOIN
sys.index_columns AS ic
ON tc.[object_id] = ic.[object_id]
AND tc.column_id = ic.column_id
AND tc.column_id = d.referenced_minor_id
INNER JOIN
sys.columns AS vc
ON vc.[object_id] = v.[object_id]
AND vc.name = tc.name -- the part I don't like
INNER JOIN
sys.indexes AS i
ON ic.[object_id] = i.[object_id]
AND i.is_primary_key = 1
ORDER BY
t.name,
ic.key_ordinal;
GO
DROP VIEW dbo.view_boo, dbo.view_foo;
DROP TABLE dbo.foo, dbo.boo;

How can I identify unused/redundant columns given a list of tables?

[This is on an iSeries/DB2 database if that makes any difference]
I want to write a procedure to identify columns that are left as blank or zero (given a list of tables).
Assuming I can pull out table and column definitions from the central system tables, how should I check the above condition? My first guess is for each column generate a statement dynamically such as:
select count(*) from my_table where my_column != 0
and to check if this returns zero rows, but is there a better/faster/standard way to do this?
NB This just needs to handle simple character, integer/decimal fields, nothing fancy!
To check for columns that contain only NULLs on DB2:
Execute RUNSTATS on your database (http://www.ibm.com/developerworks/data/library/techarticle/dm-0412pay/)
Check the database statistics by quering SYSSTAT.TABLES and SYSSTAT.COLUMNS . Comparing SYSSTAT.TABLES.CARD and SYSSTAT.COLUMNS.NUMNULLS will tell you what you need.
An example could be:
select t.tabschema, t.tabname, c.colname
from sysstat.tables t, sysstat.columns c
where ((t.tabschema = 'MYSCHEMA1' and t.tabname='MYTABLE1') or
(t.tabschema = 'MYSCHEMA2' and t.tabname='MYTABLE2') or
(...)) and
t.tabschema = c.tabschema and t.tabname = c.tabname and
t.card = c.numnulls
More on system stats e.g. here: http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/admin/r0001070.htm and http://publib.boulder.ibm.com/infocenter/db2luw/v8/index.jsp?topic=/com.ibm.db2.udb.doc/admin/r0001073.htm
Similarly, you can use SYSSTAT.COLUMNS.AVGCOLLEN to check for empty columns (just it doesn't seem to work for LOBs).
EDIT: And, to check for columns that contain only zeros, use try comparing HIGH2KEY and LOW2KEY in SYSSTAT.COLUMNS.
Yes, typically, I would do something like this in SQL Server:
SELECT
REPLACE(REPLACE(REPLACE(
'
SELECT COUNT(*) AS [COUNT NON-EMPTY IN {TABLE_NAME}.{COLUMN_NAME}]
FROM [{TABLE_SCHEMA}].[{TABLE_NAME}]
WHERE [{COLUMN_NAME}] IS NOT NULL
OR [{COLUMN_NAME}] <> 0
'
, '{TABLE_SCHEMA}', c.TABLE_SCHEMA)
, '{TABLE_NAME}', c.TABLE_NAME)
, '{COLUMN_NAME}', c.COLUMN_NAME) AS [SQL]
FROM INFORMATION_SCHEMA.COLUMNS c
INNER JOIN INFORMATION_SCHEMA.TABLES t
ON t.TABLE_TYPE = 'BASE TABLE'
AND c.TABLE_CATALOG = t.TABLE_CATALOG
AND c.TABLE_SCHEMA = t.TABLE_SCHEMA
AND c.TABLE_NAME = t.TABLE_NAME
AND c.DATA_TYPE = 'int'
You can get a lot fancier by doing UNIONs of the entire query and checking the IS_NULLABLE on each column and obviously you might have different requirements for different data types, and skipping identity columns, etc.
I'm assuming you mean you want to know if there are any values in all the rows of a given column. If your column can have "blanks" you're probably going to need to add an OR NOT NULL to your WHERE clause to get the correct answer.