Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
AskSQLTeam
Ask SQLTeam Question
0 Posts |
Posted - 2004-11-15 : 07:57:44
|
| Tyler writes "Hello,I support an application that uses GUIDs all over in it's database. In order to troubleshoot application errors and to better understand relationships between the tables in the database I've written a query to search a database for a specified GUID. My problem is that I'm not a SQL expert and I'm sure the query is not optimal. I'm using a cursor :( as I have been unable to figure out any other way to get the data I want. Please have a look at my query below and let me know if you can figure out a way to not use the cursor as well as any other optimization suggestions you come up with.Thanks,Tyler--Temporary table to hold Table and Column names that are related to GUID as well as the number of rows CREATE TABLE #TablesWithGuid (Tablename varchar(255), ColName varchar(255), Rows int) DECLARE @TableName varchar(255), @ColName varchar(255), @GUID varchar(40), @xtype int, @SqlResult int, @strSql nvarchar(4000) --GUID that is being searched for.SET @GUID = RTRIM(LTRIM('ENTER GUID HERE')) --Drop outside characters if longer than 36. (Eg. { and } characters)IF LEN(@GUID) = 38 BEGIN SET @GUID = SUBSTRING(@GUID, 2, 36) END DECLARE GuidTableCol CURSOR FOR -- Tables with a '%guid%' column name or Uniqueidentifier column. Column name as well. SELECT DISTINCT CAST(so.[name] AS varchar(255)) AS [Table Name], CAST(co.[name] AS varchar(255)) AS [Guid Column], co.[xtype] FROM sysobjects so INNER JOIN (SELECT [name], [id], [xtype] FROM syscolumns WHERE (lower([name]) LIKE '%guid%') OR ([xtype] = 36)) co ON co.[id] = so.[id] WHERE (so.[xtype] = 'U') --Only User Tables OPEN GuidTableCol FETCH NEXT FROM GuidTableCol INTO @TableName, @ColName, @xtype WHILE @@FETCH_STATUS = 0 BEGIN /* Find which tables and columns have a matching Guid to the one we are searching for. Return COUNT of matching rows as well. */ SET @SqlResult = 0 --change guid string to have brackets for cases when the column is a varchar or nvarchar IF @xtype IN (167,231) BEGIN SET @GUID = '{' + @GUID + '}' END SET @strSql = 'SELECT @Result = COUNT(CAST([' + @ColName + '] AS varchar(255))) FROM [' + @TableName + '] WHERE CAST([' + @ColName + '] AS varchar(255)) = ''' + @GUID + '''' /* @ColName is CAST as a varchar type since the COUNT function will not work on uniqueidentifier types. Since the @ColName is cast as a varchar, brackets {} cannot be used in the @GUID string if the column is a uniqueidentifier. Otherwise the uniqueidentifier columns will not match up with the @GUID string. */ EXECUTE sp_executesql @strSql, N'@Result int out', @SqlResult out IF @SqlResult > 0 --If the result count is > 0 then add table, column, and count to #TablesWithGuid BEGIN INSERT INTO #TablesWithGuid VALUES (@TableName, @ColName, @SqlResult) END IF @xtype IN (167,231) --reset guid string if column is varchar or nvarchar BEGIN SET @GUID = SUBSTRING(@GUID, 2, 36) END FETCH NEXT FROM GuidTableCol INTO @TableName, @ColName, @xtype END CLOSE GuidTableCol DEALLOCATE GuidTableCol SELECT * FROM #TablesWithGuid DROP TABLE #TablesWithGuid" |
|
|
tkeith
Starting Member
9 Posts |
Posted - 2004-12-02 : 12:57:25
|
With the help of the How to Perform SQL Server Row-by-Row Operations Without Cursors article on sql-server-performance.com I was able to use a loop instead of my cursor. I also made a few other changes based on some recommendations of a friend. -TylerHere's my new query:/* Temporary table to hold all columns that have a GUID name or uniqueidentifier type. Holds an ID value (for looping), the table name and the column type as well. */DECLARE @TablesToBeSearched TABLE(RowId smallint IDENTITY(1,1) , TableName varchar(255) , ColName varchar(128) , ColType varchar(128))--Temporary table to hold Table and Column names that are related to GUID DECLARE @TablesWithGuid TABLE(TableName varchar(255), ColName varchar(128), RowsFound int) DECLARE @TableName varchar(255), @ColName varchar(255), @GUID varchar(40), @ColType varchar(128), @SqlResult int, @strSql nvarchar(4000), @currentrow smallint, @nextrow smallint, @loopcontrol smallint--GUID that is being searched for.SET @GUID = RTRIM(LTRIM('ENTER GUID HERE')) --Drop { and } characters if present. Return if invalid guid entered.IF LEN(@GUID) = 38 AND CHARINDEX('{',@GUID,1) = 1 AND CHARINDEX('}',@GUID,1) = 38BEGIN SET @GUID = SUBSTRING(@GUID, 2, 36) END ELSE IF LEN(@GUID) <> 36BEGIN SELECT 'Invalid Guid Specified' AS [ERROR] RETURNEND-- Get meta data for columns and tables that are GUIDsINSERT INTO @TablesToBeSearchedSELECT isc.[TABLE_NAME], isc.[COLUMN_NAME], isc.[DATA_TYPE]FROM INFORMATION_SCHEMA.[Columns] isc INNER JOIN INFORMATION_SCHEMA.Tables ist ON isc.[TABLE_NAME] = ist.[TABLE_NAME]WHERE ((LOWER(isc.[Column_Name]) LIKE '%guid%' AND isc.[Data_Type] IN ('char','varchar','nchar','nvarchar') AND COL_LENGTH((isc.[TABLE_NAME]),isc.[COLUMN_NAME]) > 35) OR isc.[Data_Type] = 'uniqueidentifier') AND ist.[TABLE_TYPE] = 'BASE TABLE'--Initialize loop variablesSELECT @loopcontrol = 1SELECT @nextrow = MIN(RowId)FROM @TablesToBeSearched--Make sure table has dataIF ISNULL(@nextrow,0) = 0BEGIN SELECT 'No Guid columns found in the ' + DB_NAME() + ' database' AS [ERROR] RETURNEND-- Retrieve the first rowSELECT @currentrow = [RowId], @TableName = [TableName], @ColName = [ColName], @ColType = [ColType]FROM @TablesToBeSearchedWHERE RowId = @nextrowWHILE @loopcontrol = 1 BEGIN /* Find which tables and columns have a matching Guid to the one we are searching for. Return COUNT of matching rows as well. */ SET @SqlResult = 0 --change guid string to have brackets for cases when the column is a varchar or nvarchar IF @ColType IN ('char','varchar','nchar','nvarchar') BEGIN SET @GUID = '{' + @GUID + '}' END SET @strSql = 'SELECT @Result = COUNT(CAST([' + @ColName + '] AS varchar(255))) FROM [' + @TableName + '] WHERE CAST([' + @ColName + '] AS varchar(255)) = ''' + @GUID + '''' /* @ColName is CAST as a varchar type since the COUNT function will not work on uniqueidentifier types. Since the @ColName is cast as a varchar, brackets {} cannot be used in the @GUID string if the column is a uniqueidentifier. Otherwise the uniqueidentifier rows will not match up with the @GUID string. */ EXECUTE sp_executesql @strSql, N'@Result int out', @SqlResult out --If the result count is > 0 then add table, column, and count to @TablesWithGuid IF @SqlResult > 0 BEGIN INSERT INTO @TablesWithGuid VALUES (@TableName, @ColName, @SqlResult) END --reset guid string if column is not a uniqueidentifier IF @ColType IN ('char','varchar','nchar','nvarchar') BEGIN SET @GUID = SUBSTRING(@GUID, 2, 36) END -- Reset looping variables. SELECT @nextrow = NULL -- get the next RowId SELECT @nextrow = MIN(RowId) FROM @TablesToBeSearched WHERE [RowId] > @currentrow -- did we get a valid next row id? IF ISNULL(@nextrow,0) = 0 BEGIN BREAK END -- get the next row. SELECT @currentrow = [RowId] , @TableName = [TableName] , @ColName = [ColName] , @ColType = [ColType] FROM @TablesToBeSearched WHERE RowId = @nextrow END SELECT * FROM @TablesWithGuid ORDER BY TableName, ColName |
 |
|
|
Bustaz Kool
Master Smack Fu Yak Hacker
1834 Posts |
Posted - 2004-12-05 : 09:01:56
|
| Why are you storing a GUID in a char, varchar, nvarchar or nchar column?HTH=========================================Let X = {All sets s such that s is not an element of s}(X element of X) ==> (X not element of X)(X not element of X) ==> (X element of X) (Bertrand Russell Paradox) |
 |
|
|
tkeith
Starting Member
9 Posts |
Posted - 2004-12-07 : 14:19:11
|
| Good question, I didn't write the application though, and I wasn't involved in designing the database so I really don't know. I just get to support the application. I found there were a few columns where Guids were stored as a varchar or nvarchar. The only thing that helped me identify them as a guid was that 'guid' was part of the column name. So I just expanded the search to include char, nchar, varchar, and nvarchar columns with a name LIKE '%guid%'.-TK |
 |
|
|
|
|
|
|
|