SQL Server:搜索所有表中的特定 GUID
我遇到了清理一些数据的需要,并且我需要在 SQL Server° 中找到一些特定的 guid(即唯一标识符)。
我提出了一个存储过程,它从当前数据库中每个表中的每个 uniqueidentifier 列执行 SELECT 操作,如果找到 guid,则返回一个结果集。
它使用 INFORMATION_SCHEMA 视图查找所有基表中的所有uniqueidentifier列(而不是视图)。 对于每一列,它发出一个选择,返回表的名称和找到它的列。
CREATE PROCEDURE dbo.FindGUID @searchValue uniqueidentifier AS
/*
Search all tables in the database for a guid
6/9/2009: Removed the IF EXISTS to double hit the database
*/
--DECLARE @searchValue uniqueidentifier
--SET @searchValue = '{2A6814B9-8261-452D-A144-13264433864E}'
DECLARE abc CURSOR FOR
SELECT
c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns c
INNER JOIN INFORMATION_SCHEMA.Tables t
ON c.TABLE_NAME = t.TABLE_NAME
AND t.TABLE_TYPE = 'BASE TABLE'
WHERE DATA_TYPE = 'uniqueidentifier'
DECLARE @tableName varchar(200)
DECLARE @columnName varchar(200)
DECLARE @szQuery varchar(8000)
OPEN ABC
FETCH NEXT FROM abc INTO @tableName, @columnName
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @szQuery =
'SELECT '''+@tableName+''' AS TheTable, '''+@columnName+''' AS TheColumn '+
'FROM '+@tableName+' '+
'WHERE '+@columnName+' = '''+CAST(@searchValue AS varchar(50))+''''
PRINT 'Searching '+@tableName+'.'+@columnName+'..'
PRINT @szQuery
EXEC (@szQuery)
FETCH NEXT FROM abc INTO @tableName, @columnName
END
CLOSE abc
DEALLOCATE abc
我的问题是:
问题 1
任何人都可以找到一种方法来更改它以在同一个表中执行多个 uniqueidentifier 列的搜索作为 OR,而不是单独的查询,
即
SELECT ... FROM Prices WHERE BookGUID = '{...}'
SELECT ... FROM Prices WHERE AuthorGUID = '{...}'
SELECT ... FROM Prices WHERE PublisherGUID = '{...}'
SELECT ... FROM Prices WHERE StoreGUID = '{...}'
会变成:
SELECT ...
FROM Prices
WHERE BookGUID = '{...}'
OR AuthorGUID = '{...}'
OR PublisherGUID = '{...}'
OR StoreGUID = '{...}'
我尝试在游标内使用游标,但是 FETCH_STATUS 的冲突。
问题2 谁能想到更好的方法来做到这一点? ‡
脚注:
° SQL Server 2000
‡ 受到在关系数据库中使用唯一标识符的约束。
i came across the need to cleanse some data, and i need to find some particular guids (i.e. uniqueidentifiers) in SQL Server°.
i've come up with a stored procedure that does a SELECT from every uniqueidentifier column in every table in the current database, and returns a result set if the guid is found.
It uses the INFORMATION_SCHEMA views to find all uniqueidentifier columns in all base tables (as opposed to views). For each column it issues a select, returning the name of the table and the column where it was found.
CREATE PROCEDURE dbo.FindGUID @searchValue uniqueidentifier AS
/*
Search all tables in the database for a guid
6/9/2009: Removed the IF EXISTS to double hit the database
*/
--DECLARE @searchValue uniqueidentifier
--SET @searchValue = '{2A6814B9-8261-452D-A144-13264433864E}'
DECLARE abc CURSOR FOR
SELECT
c.TABLE_NAME, c.COLUMN_NAME
FROM INFORMATION_SCHEMA.Columns c
INNER JOIN INFORMATION_SCHEMA.Tables t
ON c.TABLE_NAME = t.TABLE_NAME
AND t.TABLE_TYPE = 'BASE TABLE'
WHERE DATA_TYPE = 'uniqueidentifier'
DECLARE @tableName varchar(200)
DECLARE @columnName varchar(200)
DECLARE @szQuery varchar(8000)
OPEN ABC
FETCH NEXT FROM abc INTO @tableName, @columnName
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @szQuery =
'SELECT '''+@tableName+''' AS TheTable, '''+@columnName+''' AS TheColumn '+
'FROM '+@tableName+' '+
'WHERE '+@columnName+' = '''+CAST(@searchValue AS varchar(50))+''''
PRINT 'Searching '+@tableName+'.'+@columnName+'..'
PRINT @szQuery
EXEC (@szQuery)
FETCH NEXT FROM abc INTO @tableName, @columnName
END
CLOSE abc
DEALLOCATE abc
My question are:
Question 1
Could anyone figure out a way to change it to perform a search of multiple uniqueidentifier columns in the same table as ORs, rather than separate queries
i.e.
SELECT ... FROM Prices WHERE BookGUID = '{...}'
SELECT ... FROM Prices WHERE AuthorGUID = '{...}'
SELECT ... FROM Prices WHERE PublisherGUID = '{...}'
SELECT ... FROM Prices WHERE StoreGUID = '{...}'
would become:
SELECT ...
FROM Prices
WHERE BookGUID = '{...}'
OR AuthorGUID = '{...}'
OR PublisherGUID = '{...}'
OR StoreGUID = '{...}'
i tried using a cursor inside a cursor, but the FETCH_STATUS's conflict.
Question 2
Can anyone think of any better way to do it?‡
Footnotes:
° SQL Server 2000
‡ Subject to the constraint of using uniqueidentifiers in a relational database.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
听起来您基本上想将列列表连接到动态 sql 中。 mssql 中没有一流的 concat 函数,您可以编写自己的 CLR udf 来执行此操作,但我不喜欢该解决方案。 检查 这个问题对于一些mssql concat解决方案。
Sounds like you basically want to concatenate the list of columns into your dynamic sql. There isn't a first class concat function in mssql, you can write your own CLR udf to do it but I don't love that solution. Check this question for some mssql concat solutions.
看起来这里的工程有点过了……你说你只需要“找到一些特定的指导”。 导出整个数据库然后在记事本++中打开它并搜索您想要的指南可能会更容易。 然后您将看到当时的整行数据等。
您可以阅读有关将数据库导出到文本文件的 SQL Server 发布向导
这里。
Looks like a little over engineering going on here.... You said you just needed to "find some particular guids". It might be easier to export the whole database and then open it up in notepad++ and search for the guids you wanted. Then you will be seeing the whole row of data at that time, etc.
You can read about the SQL Server Publishing Wizard that exports the database to a text file
here.
您可以推迟执行,直到光标循环完成。 然后,只需跟踪循环内的表名称,如果相同,则添加一个 OR,否则结束 SELECT 并开始新的 SELECT。
您还可以创建存储过程来构建一个 VIEW,该 VIEW 对所有表和 uniqueidentifier 字段执行 UNION ALL。 具有这样的架构:
然后,您只需在这个可重用的 VIEW 上执行单个 SELECT 语句即可获取所有匹配的 GUID。 要在单个表中搜索,请使用相关子查询,例如:
这将搜索价格表中的所有 GUID 字段。 SQL Server 足够智能,不会查找其他表,而是使用现有表的索引。
通过重用单个视图,您只需在更改架构时循环访问 information_schema,而不是每次查询,并且视图的结果比存储过程的结果更容易连接。
答案
原始海报最终解决方案,基于此答案:
You could defer the EXEC until your cursor loop is done. Then, just track the table name inside your loop and if it's the same, add an OR, otherwise end your SELECT and start a new one.
You could also create the stored procedure to build a VIEW that does a UNION ALL of all tables and uniqueidentifier fields. Something with a schema like this:
Then, you just need to perform a single SELECT statement on this reusable VIEW to get all of the matching GUIDs. To search within a single table, use a correlated subquery, e.g.:
That will search across all GUID fields in the prices table. SQL Server is smart enough to not go looking through other tables, and it uses your existing tables' indexes.
By re-using a single view, you only have to go looping through information_schema when you change your schema, not with every query, and the results of a view can be joined more readily than the results of a stored procedure.
Answer
Original posters final solution, based on this answer:
您可以将所有内容包装到一个 SELECT 中并立即搜索所有表:
我使用了像“OR 0=1”这样的逻辑删除终止符,甚至使用了整个 UNION,但这只是因为我太懒了,无法从构建的串联中修剪结尾字符串。
You can wrap all into a single SELECT and search all tables at once:
I used tombstone terminators like 'OR 0=1' and even an entire UNION, but that is just because I'm too lazy to trim the ending from the built concatenated strings.
这是针对 SQL 2000 的解决方案,无偿使用游标:
这是针对 SQL 2005 的解决方案,基于 Remus 的解决方案,并使用临时表来实现更好的扩展:
Here's a solution for SQL 2000, with gratuitous use of cursors:
Here's a solution for SQL 2005, based on Remus's solution, with temp tables for better scaling:
我发现评分最高的脚本有点慢,所以我把这个放在一起。 它对我来说速度更快,并且还返回行数。 享受。
I found the top rated script to be a bit slow, so I put together this one. It's faster for my use, and it returns a row count also. Enjoy.