เวอร์ชั่นของฉัน ...
ฉันตั้งชื่อมันว่า "เข็มในกองหญ้า" ด้วยเหตุผลที่ชัดเจน
ค้นหาค่าเฉพาะในแต่ละแถวและแต่ละคอลัมน์ไม่ใช่สำหรับชื่อคอลัมน์เป็นต้น
ดำเนินการค้นหา (แทนที่ค่าสำหรับตัวแปรสองตัวแรกแน่นอน):
DECLARE @SEARCH_DB VARCHAR(100)='REPLACE_WITH_YOUR_DB_NAME'
DECLARE @SEARCH_VALUE_LIKE NVARCHAR(100)=N'%REPLACE_WITH_SEARCH_STRING%'
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM information_schema.columns WHERE TABLE_CATALOG=@SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime');
DECLARE @TOTAL int = (SELECT COUNT(*)
FROM information_schema.columns WHERE TABLE_CATALOG=@SEARCH_DB AND DATA_TYPE NOT IN ('timestamp', 'datetime'));
DECLARE @TABLE_CATALOG nvarchar(500), @TABLE_SCHEMA nvarchar(500), @TABLE_NAME nvarchar(500), @COLUMN_NAME nvarchar(500), @DATA_TYPE nvarchar(500);
DECLARE @SQL nvarchar(4000)='';
PRINT '-------- BEGIN SEARCH --------';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO @TABLE_CATALOG, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME, @DATA_TYPE;
BEGIN TRY DROP TABLE ##RESULTS; END TRY BEGIN CATCH END CATCH
CREATE TABLE ##RESULTS( TABLE_CATALOG nvarchar(500), TABLE_SCHEMA nvarchar(500), TABLE_NAME nvarchar(500), COLUMN_NAME nvarchar(500), DATA_TYPE nvarchar(500), RECORDS int)
DECLARE @SHOULD_CAST bit=0
DECLARE @i int =0
DECLARE @progress_sum bigint=0
WHILE @@FETCH_STATUS = 0
BEGIN
-- PRINT '' + CAST(@i as varchar(100)) +' of ' + CAST(@TOTAL as varchar(100)) + ' ' + @TABLE_CATALOG+'.'+@TABLE_SCHEMA+'.'+@TABLE_NAME+': '+@COLUMN_NAME+' ('+@DATA_TYPE+')';
SET @SHOULD_CAST = (SELECT CASE @DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET @SQL='SELECT '''+@TABLE_CATALOG+''' catalog_name, '''+@TABLE_SCHEMA+''' schema_name, '''+@TABLE_NAME+''' table_name, '''+@COLUMN_NAME+''' column_name, '''+@DATA_TYPE+''' data_type, ' +
+' COUNT(['+@COLUMN_NAME+']) records '+
+' FROM '+@TABLE_CATALOG+'.'+@TABLE_SCHEMA+'.'+@TABLE_NAME +
+' WHERE ' + CASE WHEN @SHOULD_CAST=1 THEN 'CAST(['+@COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+@COLUMN_NAME + '] ' END
+' LIKE '''+ @SEARCH_VALUE_LIKE + ''' '
-- PRINT @SQL;
IF @i % 100 = 0
BEGIN
SET @progress_sum = (SELECT SUM(RECORDS) FROM ##RESULTS)
PRINT CAST (@i as varchar(100)) +' of ' + CAST(@TOTAL as varchar(100)) +': '+ CAST (@progress_sum as varchar(100))
END
INSERT INTO ##RESULTS (TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, RECORDS)
EXEC(@SQL)
FETCH NEXT FROM col_cur INTO @TABLE_CATALOG, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME, @DATA_TYPE;
SET @i=@i+1
-- IF @i > 1000
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
SELECT * FROM ##RESULTS WHERE RECORDS>0;
จากนั้นหากต้องการดูผลลัพธ์แม้ในขณะดำเนินการจากหน้าต่างอื่นให้ดำเนินการ:
DECLARE @SEARCH_VALUE_LIKE NVARCHAR(100)=N'%@FLEX@%'
SELECT * FROM ##RESULTS WHERE RECORDS>0;
SET NOCOUNT ON;
DECLARE col_cur CURSOR FOR
SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM ##RESULTS WHERE RECORDS>0;
DECLARE @TABLE_CATALOG nvarchar(500), @TABLE_SCHEMA nvarchar(500), @TABLE_NAME nvarchar(500), @COLUMN_NAME nvarchar(500), @DATA_TYPE nvarchar(500);
DECLARE @SQL nvarchar(4000)='';
OPEN col_cur;
FETCH NEXT FROM col_cur INTO @TABLE_CATALOG, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME, @DATA_TYPE;
DECLARE @i int =0
DECLARE @SHOULD_CAST bit=0
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SHOULD_CAST = (SELECT CASE @DATA_TYPE
WHEN 'varchar' THEN 0
WHEN 'nvarchar' THEN 0
WHEN 'char' THEN 0
ELSE 1 END)
SET @SQL='SELECT '''+@TABLE_CATALOG+''' catalog_name, '''+@TABLE_SCHEMA+''' schema_name, '''+@TABLE_NAME+''' table_name, '''+@COLUMN_NAME+''' column_name, '''+@DATA_TYPE+''' data_type, ' +
+' ['+@COLUMN_NAME+']'+
+', * '
+' FROM '+@TABLE_CATALOG+'.'+@TABLE_SCHEMA+'.'+@TABLE_NAME +
+' WHERE ' + CASE WHEN @SHOULD_CAST=1 THEN 'CAST(['+@COLUMN_NAME + '] as NVARCHAR(max)) ' ELSE ' ['+@COLUMN_NAME + '] ' END
+' LIKE '''+ @SEARCH_VALUE_LIKE + ''' '
PRINT @SQL;
EXEC(@SQL)
FETCH NEXT FROM col_cur INTO @TABLE_CATALOG, @TABLE_SCHEMA, @TABLE_NAME, @COLUMN_NAME, @DATA_TYPE;
SET @i=@i+1
-- IF @i > 10
-- BREAK
END
CLOSE col_cur;
DEALLOCATE col_cur;
มีบางคนกล่าวถึงเรื่องนี้:
- มันใช้เคอร์เซอร์แทนการบล็อกในขณะที่วนซ้ำ
- สามารถพิมพ์ความคืบหน้า (ไม่แสดงความคิดเห็นหากจำเป็น)
- มันสามารถออกได้หลังจากพยายามสองสามครั้ง (ไม่ใส่เครื่องหมาย IF ในตอนท้าย)
- จะแสดงบันทึกทั้งหมด
- คุณสามารถปรับแต่งได้ตามต้องการ
ความรับผิดชอบ:
- อย่าใช้งานในสภาพแวดล้อมการผลิต!
- มันเป็นช้า หากบริการ / ผู้ใช้อื่นเข้าถึงฐานข้อมูลได้โปรดเพิ่ม "ด้วย (NOLOCK)" หลังทุกชื่อตารางในการเลือกทั้งหมดโดยเฉพาะอย่างยิ่งรายการเลือกแบบไดนามิก
- ไม่ตรวจสอบ / ป้องกันตัวเลือกการฉีด SQL ทุกประเภท
- หากฐานข้อมูลของคุณมีขนาดใหญ่ให้เตรียมตัวสำหรับการนอนหลับตรวจสอบให้แน่ใจว่าแบบสอบถามจะไม่ถูกฆ่าหลังจากผ่านไปสักครู่
- มันร่ายค่าบางอย่างให้กับสตริงรวมถึง ints / bigints / smallints / tinyints หากคุณไม่ต้องการสิ่งเหล่านี้ให้วางไว้ในรายการยกเว้นเดียวกันโดยมีการประทับเวลาที่ด้านบนของสคริปต์