Is there a script out there that will let MSSQL find columns with records that have the same data in multiple tables.
What I want to do is find the primary keys to data tables that we imported from excel spread sheets that were made from another database.
Thanks,
Chris
You're going to want to look up the SysObjects and SysColumn system tables, very handy for this sort of thing.
Here's an example that looks through all tables for the integer value 500. Note that if you want to look for a different type of column you'll need to change the xtype. It's not a full blown "Compare every column in my database against every other column" example however it should give you the basic idea and hopefully get you started.
Additionally I'm using a memory table for this example. If your database is large you will want to use a temporary table and a cursor likely.
This returns a single column recordset with the value of "Table - ColumnName = Search Value"
-- declare my search table
DECLARE #Columns TABLE (TableName varchar(50), ColumnName varchar(50))
DECLARE #Results TABLE (Results VARCHAR(255))
DECLARE #SearchData INT
SET #SearchData = 500
DECLARE #TableName VARCHAR(50)
DECLARE #ColumnName VARCHAR(50)
DECLARE #Command VARCHAR(1024)
-- Find all tables with an integer column
Insert INTO #Columns
Select sysobjects.[Name] as TableName, syscolumns.[Name] as ColumnName
from dbo.sysobjects INNER Join dbo.syscolumns ON dbo.sysobjects.id = dbo.syscolumns.id
Where sysobjects.xtype = 'U' and syscolumns.xtype = 56 Order By TableName, ColumnName
--Loop!
WHILE NOT (Select TOP 1 TableName from #Columns) IS NULL
BEGIN
Select TOP 1 #TableName = TableName, #ColumnName = ColumnName from #Columns
SET #Command = 'Select ''' + #TableName + ' - ' + #ColumnName + ' = ' + CAST(#SearchData as varchar(32)) + ''' FROM ' + #TableName + ' WHERE ' + #ColumnName + ' = ' + CAST(#SearchData as VARCHAR(32))
Insert INTO #Results
exec(#Command)
Delete from #Columns where TableName = #TableName AND ColumnName = #ColumnName
END
-- Export all results
Select * from #Results
Related
I have almost 1000 tables and most of them have a common column ItemNumber. How do I search across all the tables in the database for a value or list of values that exist in this common column, such as 350 or (350, 465)? The tables have different schemas.
Table A100
ItemNumber
Detail
230
Car
245
Plane
Table A1000
ItemNumber
ProductDescription
350
Pie
465
Cherry
This does not perform type checking, so you can get conversion errors if the target column is not the correct type. Also, this script uses LIKE, you would probably need to change that to a direct comparison.
SET NOCOUNT ON
DECLARE #ID NVARCHAR(100) = '2'
DECLARE #ColumnName NVARCHAR(100) ='UserID'
DECLARE #Sql NVARCHAR(MAX)=N'CREATE TABLE #TempResults(TableName NVARCHAR(50), ColumnName NVARCHAR(50), ItemCount INT)'
SELECT
#Sql = #Sql + N'INSERT INTO #TempResults SELECT * FROM (SELECT '''+ST.Name+''' AS TableName, '''+C.Name+''' AS ColumnName, COUNT(*) AS ItemCount FROM '+ST.Name+' WHERE '+C.Name+'='+#ID+') AS X WHERE ItemCount > 0 '
FROM
sys.columns C
INNER JOIN sys.tables ST ON C.object_id = ST.object_id
WHERE
C.Name LIKE '%'+#ColumnName+'%'
SET #Sql = #Sql + N'SELECT * FROM #TempResults'
exec sp_executesql #sql
You need to do this with dynamic SQL. You will need to query all 1000 tables, and make sure you are converting the values correctly if the columsn are different types.
You don't need a temp table for this, you can just script one giant UNION ALL query. You must make sure to quote all dynamic names correctly using QUOTENAME.
To be able to return data for multiple items, you should create a Table Valued Parameter, which you can pass in using sp_executesql.
First create a table type
CREATE TYPE dbo.IntList (Id int PRIMARY KEY);
Then you create a table variable containing them, and pass it in. You can also do this in a client application and pass in a TVP.
SET NOCOUNT ON;
DECLARE #Items dbo.IntList;
INSERT #Items (Id) VALUES(350),(465);
DECLARE #Sql nvarchar(max);
SELECT
#Sql = STRING_AGG(CONVERT(nvarchar(max), N'
SELECT
' + QUOTENAME(t.name, '''') + ' AS TableName,
t.ItemNumber,
COUNT(*) AS ItemCount
FROM ' + QUOTENAME(t.Name) + ' t
JOIN #items i ON i.Id = t.ItemNumber
GROUP BY
t.ItemNumber
HAVING COUNT(*) > 0
' ),
N'
UNION ALL
' )
FROM
sys.tables t
WHERE t.object_id IN (
SELECT c.object_id
FROM sys.columns c
WHERE
c.Name = 'ItemNumber'
);
PRINT #sql; -- your friend
EXEC sp_executesql
#sql,
N'#items dbo.IntList',
#items = #items READONLY;
If you don't need to know the count, and only want to know if a value exists, you can change the dynamic SQL to an EXISTS
....
SELECT
#Sql = STRING_AGG(CONVERT(nvarchar(max), N'
SELECT
' + QUOTENAME(t.name, '''') + ' AS TableName,
t.ItemNumber
FROM #items i
WHERE i.Id IN (
SELECT t.ItemNumber
FROM ' + QUOTENAME(t.Name) + ' t
)
' ),
N'
UNION ALL
' )
....
Good afternoon,
I have a working query, where I loop through all my databases, and filter down to check which report is being used where. This works (see below)
I have this working query:
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
ReportPath VARCHAR(500)
)
declare #SQL nvarchar(max)
set #SQL = STUFF((SELECT '
UNION ALL
' + 'SELECT path FROM ' + quotename(name) + '.dbo.ReportConfig where path like ''%/Standard Reports/Booking/Booked Out by Location%'' and Active = 1'
from sys.Databases
WHERE name LIKE 'SFB-%'
FOR XML PATH(''), type).value('.','varchar(max)'),1,15,'')
INSERT #temp
execute(#SQL)
SELECT ReportPath FROM #temp
And this is giving me the following output:
So I know that out of my 90 databases, the report is being used 6 times, but I don't know where.
So I want to include the database name of where this report is being used.
I googled around and tried a bunch of things, but I can't get it to work.
Any ideas?
Just a small tweak to what you already have will get you there
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
--Add a column to your temp table
CREATE TABLE #temp
(
DatabaseName varchar(100)
,ReportPath VARCHAR(500)
)
declare #SQL nvarchar(max)
--adjust your dynamic query and add the [name] column as shown below
set #SQL = STUFF((SELECT '
UNION ALL
' + 'SELECT ''' + [name] + ''' as DatabaseName,path FROM ' + quotename(name) + '.dbo.ReportConfig where path like ''%/Standard Reports/Booking/Booked Out by Location%'' and Active = 1'
from sys.Databases
WHERE name LIKE 'SFB-%'
FOR XML PATH(''), type).value('.','varchar(max)'),1,15,'')
INSERT #temp
execute(#SQL)
SELECT DatabaseName, ReportPath FROM #temp
I want someway to automate table creations as every day customer can add some columns ,remove some ,so my idea is to pass table name and columns into a table then use this table in stored procedure to automatically creates the table.
This is table that will hold tables structure
create table nada_test
(
table_name varchar(500),
col_name varchar(100),
col_type varchar(100)
)
Sample data:
insert into nada_test
values ('data', 'salary', 'int'), ('data', 'id', 'int'),
('data', 'job', 'varchar(100)')
Could someone show me how to achieve this?
How about that
CREATE TABLE T
(
TableName varchar(500),
ColName varchar(100),
ColType varchar(100)
);
INSERT INTO T VALUES
('data','salary','int'),
('data', 'id', 'int'),
('data', 'job', 'varchar(100)');
DECLARE #SQL NVARCHAR(MAX);
SELECT #SQL = N'CREATE TABLE Data ('+ STUFF((
SELECT ',' + ColName + ' ' + ColType
FROM T
FOR XML PATH('')
), 1, 1, '') + N' );'
FROM T;
SELECT #SQL [CreateTable];
--EXECUTE sp_executesql #SQL;
But that won't help you
What will happen to the data already exists in your table?
What if the table already exists, ok you can pass that by IF OBJECT_ID() .., but still, what will happen to the data already in your table?
You will face another problem even if you store the data in temp table because the structure of both tables is not the same even the datatypes of the columns.
As it already been mentioned, your approach is very vulnerable to SQL injections.
See example:
insert into #nada_test
values ('TestTable] (TestColumn int);SELECT * FROM sys.tables--', 'TestColumn', 'INT')
GO
DECLARE #TableName sysname, #ColumnName sysname, #Type VARCHAR(100), #SQL VARCHAR(2000)
WHILE EXISTS (SELECT TOP 1 1 FROM #nada_test)
BEGIN
SELECT TOP 1 #TableName = table_name, #ColumnName = [col_name], #Type = col_type FROM #nada_test
DELETE FROM #nada_test WHERE #TableName = table_name and #ColumnName = [col_name]
IF NOT EXISTS ( SELECT TOP 1 1 FROM sys.tables WHERE name = #TableName)
SET #SQL = 'CREATE TABLE [' + #TableName + '] ([' + #ColumnName + '] ' + #Type + ');'
ELSE IF NOT EXISTS ( SELECT TOP 1 1 FROM sys.columns WHERE name = #ColumnName AND object_id = OBJECT_ID(#TableName))
SET #SQL = 'ALTER TABLE [' + #TableName + '] ADD [' + #ColumnName + '] ' + #Type + ';'
ELSE
SET #SQL = 'PRINT ''TABLE name [' + #TableName + '] with column [' + #ColumnName + '] is already exists'';'
PRINT #SQL
EXEC (#SQL)
END
Generally we can use like
create table x as select * from y ;
using some existing table structure say y in this case
You can create a ddl trigger on your existing requirement i.e. if theres any change to this table
then fire the same query above.
Note: this is NOT asking
how to select a string where the column name is known.
how to select a string in ALL tables (all google results relate to this one)
This is asking search in only ONE table.
SQL returns error info conversion failed when converting the nvarchar value S3N2V5.
I want to locate the column name where S3N2V5 exists.
No manual methods please. There are 1000000 columns.
Input S3N2V5
Output columnname1ofthistable
Assuming I understand the question, here is one way to get a list of all columns from a single table that contain the search value, using CASE:
Create and populate sample table (Please save us this step in your future questions)
CREATE TABLE T
(
COL1 char(3),
COL2 char(3),
COL3 char(3),
COL4 int
)
INSERT INTO T VALUES
('abc', 'def', 'nop', 1),
('klm', 'nop', 'qrs', 2),
('tuv', 'wzy', 'zab', 3)
Build your dynamic sql:
DECLARE #Search nvarchar(5) = 'nop'
DECLARE #SQL nvarchar(max) = 'SELECT CASE #Search'
SELECT #SQL = #SQL +' WHEN '+ COLUMN_NAME + ' THEN '''+ COLUMN_NAME +''''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'T'
AND LOWER(DATA_TYPE) LIKE '%char%' -- only search char, varchar, nchar and nvarchar columns
SELECT #SQL = 'SELECT ColumnName FROM (' +
#SQL + ' END As ColumnName FROM T) x WHERE ColumnName IS NOT NULL'
Execute: (Note that using sp_executeSQL is SQL Injection safe, since we do not concatenate the search parameter into the query, but using it as a parameter)
EXEC sp_executeSQL #SQL, N'#Search nvarchar(5)', #Search
Results:
ColumnName
COL3
COL2
DECLARE #MyValue NVarChar(4000) = 'searchstring';
SELECT S.name SchemaName, T.name TableName
INTO #T
FROM sys.schemas S INNER JOIN
sys.tables T ON S.schema_id = T.schema_id;
WHILE (EXISTS (SELECT * FROM #T)) BEGIN
DECLARE #SQL NVarChar(4000) = 'SELECT * FROM $$TableName WHERE (0 = 1) ';
DECLARE #TableName NVarChar(1000) = (
SELECT TOP 1 SchemaName + '.' + TableName FROM #T
);
SELECT #SQL = REPLACE(#SQL, '$$TableName', #TableName);
DECLARE #Cols NVarChar(4000) = '';
SELECT
#Cols = COALESCE(#Cols + 'OR CONVERT(NVarChar(4000), ', '') + C.name + ') = CONVERT(NVarChar(4000), ''$$MyValue'') '
FROM sys.columns C
WHERE C.object_id = OBJECT_ID(#TableName);
SELECT #Cols = REPLACE(#Cols, '$$MyValue', #MyValue);
SELECT #SQL = #SQL + #Cols;
select substring(#SQL,charindex('.',#SQL)+1,charindex('(',#SQL)-charindex('.',#SQL)-8) as 'TableName'
EXECUTE(#SQL);
DELETE FROM #T
WHERE SchemaName + '.' + TableName = #TableName;
END;
DROP TABLE #T;
This will give you table Name and the entire row from the table which contains the searchstring.
Apart from anwswers mentioned in post : Older Post
1) (using column name) SELECT table_name,table_schema FROM INFORMATION_SCHEMA.COLUMNS WHERE column_name='sort_method';
I hope better you can take dump ( in.sql format ) and you can easily search the content using IDEs like N++.
I need to find the MAX LEN for all responses in column across many tables. Some of these column names match across tables, some don't. If they match, I need to use the column name through all the tables that it matches. So, say 10 tables with a total of 200 different column names. I created a TempCol table. I also have all the table names in a temp table. My thought is to add cols to the TempCol table for Table1MAX, Table1MIN, Table2MAX, Table2MIN etc.
This finds the MAX (IF Col_1 is in Table1):
SELECT MAX(LEN(Col_1)) FROM Table1
I'd like to fill in the TempCol table, with the values from above, but I keep hitting a wall.
Anybody have any ideas?
Here's one way, for the MAX length only; you can use it as a starting point and modify/extend it to include more information in the results table:
create table dbo.Results (
TableName sysname not null,
ColumnName sysname not null,
MaxLength int not null default 0,
primary key (TableName, ColumnName)
)
insert into dbo.Results (TableName, ColumnName)
select object_name(sc.object_id), sc.name
from sys.columns sc
join sys.types st
on sc.system_type_id = st.system_type_id
-- get data for varchar(max) columns only
where st.name = 'varchar' and sc.max_length = -1
declare #TableName sysname, #ColumnName sysname, #sql nvarchar(max)
declare TablesAndColumns cursor local fast_forward
for
select TableName, ColumnName
from dbo.Results
open TablesAndColumns
fetch next from TablesAndColumns into #TableName, #ColumnName
while ##fetch_status = 0
begin
set #sql = 'update dbo.Results set MaxLength = (select isnull(max(len(' + #ColumnName + ')),0) ' +
' from ' + #TableName + ') ' +
' where TableName = ''' + #TableName + ''' and ColumnName = ''' + #ColumnName + ''''
print #sql
exec sp_executesql #sql
fetch next from TablesAndColumns into #TableName, #ColumnName
end
close TablesAndColumns
deallocate TablesAndColumns
select * from dbo.Results
Using cursors and dynamic SQL isn't always a good idea, but for a one-time system task like this it's a reasonable approach.