How do I select only the columns with no data in them? - sql

I am trying to return only columns with no data in them (all NULL values). Is there an easy and quick way to do that with a select statement?
Thanks,

Editing based on response
This will return a list of all the columns and the number of records within it.
All you have to do is filter the output to non_null
declare #table_name as varchar(128) = ''; -- your table name here
declare #column_name as varchar(128);
declare #sql as nvarchar(4000);
declare #count_column int;
declare #tmp_table_result as table (
id int identity(1,1),
table_object_id bigint,
column_name varchar(128),
non_null_records int
);
declare csr cursor for
select name
from sys.columns where object_id = OBJECT_ID(#table_name);
open csr;
fetch next from csr into #column_name;
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql = 'select #cnt_col = count(' + #column_name + ') from ' + #table_name;
print #sql
execute sp_executesql #sql, N'#cnt_col int output', #cnt_col=#count_column OUTPUT;
insert into #tmp_table_result (table_object_id, column_name, non_null_records)
values (
object_id(#table_name),
#column_name,
#count_column
);
fetch next from csr into #column_name;
END
close csr;
deallocate csr;
select *
from #tmp_table_result

Try this:
select * from table where 1=2

Related

Update specific column in all tables base on specific value

I'm trying to update all table based on my value. This is a script Task in my SSIS package.
But I get the error:
Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done.
Code looks like this:
DECLARE #Column_name varchar(MAX)
DECLARE #Column_Datatype varchar(max)
SET #COLUMN_NAME='site_id'
SET #COLUMN_DATATYPE='varchar(10)'
------------------------------------------------Code---------------------------------------------------
GO
--Declare Variables
DECLARE #TableName VARCHAR(100)
DECLARE #TableSchema VARCHAR(100)
DECLARE #COLUMN_NAME VARCHAR(50)
DECLARE #COLUMN_NAME_UPDATE VARCHAR(50)
SET #COLUMN_NAME_UPDATE = ?
SET #COLUMN_NAME='site_id'
DECLARE #COLUMN_DATATYPE VARCHAR(50)
SET #COLUMN_DATATYPE='varchar(max)'
--Declare Cursor
DECLARE CUR CURSOR FOR
SELECT TABLE_SCHEMA,
TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
--OPEN CURSOR
OPEN CUR
--Fetch First Row
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
--Loop
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(MAX)
SET #SQL= ( SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=#TableName AND COLUMN_NAME=#COLUMN_NAME
and Table_Schema=#TableSchema)
BEGIN
SET #SQL='UPDATE '+ #TableSchema+'.'+ '[' + #TableName + ']' + ' SET '+#COLUMN_NAME + '='
+ '''' + #COLUMN_NAME_UPDATE + '''' + 'WHERE site_id IS NULL '
PRINT #SQL
EXEC ( #SQL)
END
FETCH NEXT FROM CUR INTO #TableSchema,#TableName
END
--Close and Deallocate Cursor
CLOSE CUR
DEALLOCATE CUR
I use a variable like input.
What's wrong?

Implementing a for loop in SQL to update rows

How do I write the below code in SQL? The query would update each column in the table from the result.
DECLARE #table_list NVARCHAR -- What data type do I use to hold a list?
DECLARE #column_list NVARCHAR
SET #table_list = (SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO) -- there are more than one results
SET #column_list = (SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO) -- there are more than one results
foreach(#table IN #table_list)
{
foreach(#column IN #column_list)
{
UPDATE #table
SET #column = '101211'
WHERE #column = '10120'
}
}
You can use CURSORs to act like a foreach loop:
DECLARE #table NVARCHAR(255)
DECLARE #column NVARCHAR(255)
DECLARE OUTER_CURSOR CURSOR
FOR SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO
OPEN OUTER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO #table
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE INNER_CURSOR CURSOR
FOR SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO
OPEN INNER_CURSOR
FETCH NEXT FROM INNER_CURSOR INTO #column
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE #strQuery NVARCHAR(MAX)
SET #strQuery = 'UPDATE [' + #table + '] SET [' + #column + '] = ''101211'' WHERE [' + #column + '] = ''10120'';'
EXEC(#strQUERY)
FETCH NEXT FROM INNER_CURSOR INTO #column
END
CLOSE INNER_CURSOR
DEALLOCATE INNER_CURSOR
FETCH NEXT FROM OUTER_CURSOR INTO #table
END
CLOSE OUTER_CURSOR
DEALLOCATE OUTER_CURSOR
T-SQL doesn't have a FOR loop, perhaps it has a WHILE (Transact-SQL)
Use SQL like below:
DECLARE #table_list NVARCHAR -- What data type do I use to hold a list?
DECLARE #column_list NVARCHAR
SET #table_list = (SELECT DISTINCT [ID_TABLE_NAME] FROM dbo.VMO) -- there are more than one results
SET #column_list = (SELECT DISTINCT [USR_COL_NAME] FROM dbo.VMO) -- there are more than one results
WHILE #column_list > #table_list
BEGIN
UPDATE #table
SET #column = '101211'
WHERE #column = '10120'
END;

SQL query to find all references of a particular column in a database?

I need to write some SQL to find all references of a particular column in a database. The column that I'm trying to find references to exists in a different databases. I've found a few examples of finding references of a column that exist in the same database:
In SQL Server, how can I find everywhere a column is referenced?
But I'm having problems figuring out how to do this for a column that exists in a different database. Can you provide the SQL for this? For example purposes, let's refer to the external column I'm trying to find as:
MyExternalDB.MyExternalSchema.MyExternalTable.MyExternalColumn
Ok, just run this and make sure you set your ColumnName variable
USE [master];
GO
IF OBJECT_ID('tempdb..#columns') IS NOT NULL
DROP TABLE #columns;
GO
CREATE TABLE #columns
( databaseName nvarchar(MAX),
columnid int,
columnName nvarchar(MAX),
objectid int,
objectName nvarchar(MAX));
DECLARE #databaseName sysname;
DECLARE #columnName nvarchar(MAX) = 'ColumnName';
DECLARE cur CURSOR LOCAL FORWARD_ONLY STATIC FOR
SELECT [name]
FROM [sys].[databases]
WHERE [state] = 0
AND [name] NOT IN ( 'tempdb', 'master', 'msdb', 'model' );
OPEN cur;
FETCH NEXT FROM cur
INTO #databaseName;
WHILE ( ##FETCH_STATUS != -1 )
BEGIN;
IF ( ##FETCH_STATUS != -2 )
BEGIN;
DECLARE #statement nvarchar(MAX);
SET #statement =N'Use '+ #databaseName +
N';
if EXISTS (SELECT name FROM sys.[columns] WHERE name = ''' + #columnName + ''')
BEGIN;
INSERT [#columns] ( [databaseName], [columnid], [columnName], [objectid], [objectName] )
SELECT ''' + #databaseName + N''',
c.[column_id],
c.[name],
o.[object_id],
o.[name]
FROM sys.[columns] c
INNER JOIN sys.[objects] o
ON [o].[object_id] = [c].[object_id]
WHERE c.[name] = ''' + #columnName + ''';
END;';
EXEC [sys].[sp_executesql] #stmt = #statement;
END;
FETCH NEXT FROM cur
INTO #databaseName;
END;
CLOSE cur;
DEALLOCATE cur;
SELECT * FROM [#columns];

Copy NAV Database Structure to another Database along with Data in SQL

I need to Copy a Company in NAV Database to another Company in Different Database with SQL Query. I have achived this using the code below, but if the Structure is different in the Source or Destination my code fails. Please help me in modifying it, so i can copy the Structure and Data from the Source and replace Data and Structure in the Destination.
The code is given below.
-- =============================================
-- Author: Prajeesh
-- Create date: 31.03.2015
-- Description: Function for copying comany from one database to another
-- =============================================
Create PROCEDURE [dbo].[sp_NAVCopyCompany_v2]
#sourcecompany varchar(max),
#targetdb varchar(max),
#targetcompany varchar(max)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
declare #tablename varchar(1000)
declare #columns varchar(max)
declare #columnname varchar (max)
declare #targettable varchar (max)
declare #isidentity int
declare #sqlcommand nvarchar (max) = 'select name from '+#targetdb+'.sys.all_objects where type=''U'' and object_id>0 and name like '''+#sourcecompany+'$%'''
declare #sqlcommandIdentity nvarchar (max)
declare #tablevar table(name varchar(300))
declare #columntablevar table(COLUMN_NAME varchar(300))
declare #identitytablevar table(C int)
insert into #tablevar(name) exec sp_executesql #sqlcommand
DECLARE table_cursor CURSOR for
select name from #tablevar
OPEN table_cursor
FETCH NEXT FROM table_cursor
INTO #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
--RAISERROR (#tablename, 0, 1) WITH NOWAIT
set #sqlcommand = 'SELECT COLUMN_NAME FROM '+#targetdb+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '''+#tablename+''' and COLUMN_NAME <> ''timestamp'''
DELETE from #columntablevar
insert into #columntablevar(COLUMN_NAME) exec sp_executesql #sqlcommand
DECLARE column_cursor CURSOR for select COLUMN_NAME from #columntablevar
select #columns=''
OPEN column_cursor
FETCH NEXT from column_cursor
INTO #columnname
WHILE ##FETCH_STATUS=0
BEGIN
SELECT #columns=#columns+',['+#columnname+']'
FETCH NEXT from column_cursor
INTO #columnname
END
CLOSE column_cursor;
DEALLOCATE column_cursor;
select #columns = SUBSTRING(#columns,2,LEN(#columns)-1)
--RAISERROR (#columns, 0, 1) WITH NOWAIT
select #targettable= #targetdb+'.dbo.['+#targetcompany+SUBSTRING(#tablename,LEN(#sourcecompany)+1,LEN(#tablename)-LEN(#sourcecompany)+1)+']'
--
select #isidentity=COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME =#tablename AND COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
--
set #sqlcommandIdentity = 'SELECT COUNT(*) as C FROM '+#targetdb+'.INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='''+#tablename+''' AND COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, ''IsIdentity'') = 1'
DELETE from #identitytablevar
insert into #identitytablevar(C) exec sp_executesql #sqlcommandIdentity
select #isidentity=SUM(C) FROM #identitytablevar
RAISERROR (#targettable, 0, 1) WITH NOWAIT
set #sqlcommand = ''
IF (#isidentity>0)
set #sqlcommand = #sqlcommand + 'SET IDENTITY_INSERT '+#targettable+' ON;'
set #sqlcommand = #sqlcommand + 'delete from '+#targettable+';'
set #sqlcommand = #sqlcommand + 'insert into '+#targettable+ ' ('+ #columns + ')'
+ ' select '+#columns
+ ' from ['+#tablename+']'
IF (#isidentity>0)
set #sqlcommand = #sqlcommand + ';SET IDENTITY_INSERT '+#targettable+' OFF'
--RAISERROR (#sqlcommand, 0, 1) WITH NOWAIT
exec sp_executesql #sqlcommand
FETCH NEXT FROM table_cursor
INTO #tablename
END
CLOSE table_cursor;
DEALLOCATE table_cursor;
END
The Query is called as
use SourceDatabase
exec sp_NAVCopyCompany_v2 'Source Company_','Destination Database','Destination Company'

How to do a huge search for Primary Key ID's that is used across the database where these Primary Key ID's have similar values in columns

BackDrop: We are researching why a number of accounts were missed in a process. We have went back to as far as we have data. We now have a rather large list of accounts that for whatever reason were missed. Now this process without going into too much detail is VERY VERY complex and we need to know why these accounts and only these accounts were missed. As any DataBase we have many many automated procedures that run all the time, so there is really at this point no telling what on earth happened to cause these accounts to get missed. My only bet I think at solving this is to find similarities between these accounts. Obviously we have tried looking at the more common places and have since found nothing.
Issue: I want to use SQL to return all the tablenames and columnnames in our database Where these list of accounts have the same value in a column or columns of a table. I have created a query to find tablenames, columns, and so forth but dont know how to bring it all together to create one query that will give me all the results I want. I am certain that a cursor will need to be used and lots of inner joining but I am just not sure how this should be done.
Again:
Lets say I have account numbers 123456 and 654321 and I know our DataBase has 3,000 tables with a column reference to account number with a name of either AccountNumber, AccountNum, or Account. I want to search and find all tables that have a column with the name AccountNumber, AccountNum, or Account that has a value of 123456 or 654321. Then with these tables, for each table I want to take the rows Where the column whether the name be AccountNumber, AccountNum, or Account has a value of either 123456 and 654321 and then for each of those rows I want to check each column of each row to see if the columns on a row for account number 123456 is eqaul to a column on a row for account number 654321 , if so then I want it to return the column name and the tablename. This way I can see what these accounts have in common.
ADVANCED PORTION:
IF some poor soul is able to do the above then I'd also like to create a query that will return
The tablename and when it was updated. I would get the updated value by checking each column in each table and if the column has a type of "timestamp" or a default value of "GetDate()" then that column would be used as updated. In final result set that shows were all changes have happened for those account nubmers it will order by updated.
A first approach, rustic (I'm not that used to T-SQL, I did more PL/SQL), but which may help you going further, AND TESTED IN SQL SERVER 2008. Hope it works in 2005...)
So, we create two procedures, one calling the other
The provided code can only check, in one time
- for 2 differents IDs
- for all concerned fields (Account, AccountNum, AccountNumber)
The idea (checking for AccountNumber column)
Find the tables (in table INFORMATION_SCHEMA.columns, which lists your database tables) which have a column with one of the 3 names provided
For every table found :
create a dynamic query :
select count(*) from <THE_TABLE> where <Account_column_name> IN (123456 654321);
If we have 2 results (mean that our Ids are both present in table), we launch the second procedure, with parameters : #TableName = <THE_TABLE>, #FieldName = <Account_column_name>, #FirstId = 123456, #SecondId = 654321
We find the column names for <THE_TABLE> (again in INFORMATION_SCHEMA.columns).
For every column found :
create a dynamic query
select count(*) from <THE_TABLE> as T1
inner join <THE_TABLE> as T2 on T1.<COLUMN_NAME> = T2.<COLUMN_NAME>
where T1.<Account_column_name>= 123456
and T2.<Account_column_name>= 654321
if count(*) = 1, it means that the same value exists in the same column of the same table for the given ids.
In that case, we print <THE_TABLE> and <THE_COLUMN>
To launch search, in sql management studio, just make
EXEC GetSimilarValuesForFieldAndValue 123456, 654321
and in the "Messages" part, you should have a list of "results".
CREATE procedure [dbo].[GetSimilarValuesForFieldAndValue](#FirstId int, #SecondId int)
AS
DECLARE #sql nvarchar(MAX);
DECLARE #params NVARCHAR(MAX);
DECLARE #Count int;
DECLARE #Name NVARCHAR(MAX);
DECLARE #FieldName NVARCHAR(MAX);
DECLARE db_cursor CURSOR for
select TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.columns
where COLUMN_NAME IN('Account', 'AccountNumber', 'AccountNum');
OPEN db_cursor
FETCH next from db_cursor into #Name, #FieldName
while ##FETCH_STATUS = 0
begin
select #sql =
N' SELECT #Count=Count(*) FROM ' + #Name +
N' WHERE ' +#FieldName+' IN (#FirstId,#SecondId)'
SELECT #params = N'#FieldName NVARCHAR(MAX), #FirstId int, #SecondId int, #Count int out'
EXEC sp_executesql #sql, #params, #FieldName, #FirstId, #SecondId, #Count OUT
if (#Count = 2)
begin
exec dbo.CompareFields #Name, #FieldName, #FirstId, #SecondId
end
FETCH NEXT FROM db_cursor INTO #Name, #FieldName
end
close db_cursor
DEALLOCATE db_cursor
GO
The second one :
CREATE procedure [dbo].[CompareFields](#TableName NVARCHAR(MAX), #FieldName NVARCHAR(MAX), #FirstId int, #SecondId int)
as
DECLARE #ColumnName NVARCHAR(MAX)
DECLARE #Sql NVARCHAR(MAX)
DECLARE #Params NVARCHAR(MAX)
DECLARE #Count int
DECLARE cfCursor CURSOR FOR
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME = ''+#TableName+' '
AND COLUMN_NAME <> ' '+#FieldName+''
OPEN cfCursor
FETCH next from cfCursor into #ColumnName
while ##FETCH_STATUS = 0
begin
select #Sql =
N' SELECT #Count = count(*) from ' +#TableName + ' T1 '+
N' INNER JOIN ' + #TableName + ' T2 ON T1.' +#ColumnName + ' = T2.' + #ColumnName +
N' WHERE T1.' +#FieldName + ' = '+ CAST(#FirstId as varchar) +
N' AND T2.' + #FieldName + ' = '+CAST(#SecondId as varchar)
SELECT #Params =
N'#TableName VARCHAR(MAX), #ColumnName VARCHAR(MAX), '+
N'#FieldName VARCHAR(MAX), #FirstId int, #SecondId int, #Count int out'
exec sp_executesql #sql, #Params, #TableName, #ColumnName, #FieldName, #FirstId, #SecondId, #Count OUT
if #Count = 1
begin
--print tableName and column Name if value is identic
print 'Table : ' + #TableName + ' : same value for ' + #ColumnName
end
FETCH NEXT FROM cfCursor INTO #ColumnName
end
close cfCursor
DEALLOCATE cfCursor
GO
I actually had to do this for Guids at one point. Here is the script for doing with Guids. One sec and I'll work on modifying it to suit your needs:
DECLARE #table VARCHAR(100)
DECLARE #column VARCHAR(100)
DECLARE #value INT
SET #value = '06B8BD6C-A8EC-4EB3-9562-6666EE86952D'
DECLARE table_cursor CURSOR
FOR select tbl.Name, cols.name as TableName FROM sys.columns cols JOIN
sys.tables tbl on cols.object_id = tbl.object_id
where system_type_id = 36
OPEN table_cursor
FETCH NEXT FROM table_cursor
INTO #table, #column;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(1000)
SET #SQL = 'SELECT ''' + #Table + ''' AS TBL,''' +
#column + ''' AS COL FROM [' + #table + ']
WITH(NOLOCK) WHERE ' + #column + ' = ''' + CAST(#value AS VARCHAR(50)) + ''''
print #sql
EXEC sp_executesql #Sql
FETCH NEXT FROM table_cursor
INTO #table, #column;
END
CLOSE table_cursor
DEALLOCATE table_cursor
Updated to handle for searching on a field name:
DECLARE #table VARCHAR(100)
DECLARE #column VARCHAR(100)
DECLARE #value UNIQUEIDENTIFIER
SET #value = --ENTER YOUR ACCOUNT NUMBER HERE
DECLARE table_cursor CURSOR
select tbl.Name, cols.name as TableName FROM sys.columns cols JOIN
sys.tables tbl on cols.object_id = tbl.object_id
where cols.Name = 'AccountNumber'
OR cols.Name = 'AccountNum' OR cols.Name = 'Account'
OPEN table_cursor
FETCH NEXT FROM table_cursor
INTO #table, #column;
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #SQL NVARCHAR(1000)
SET #SQL = 'SELECT ''' + #Table + ''' AS TBL,''' + #column +
''' AS COL FROM [' + #table + '] WITH(NOLOCK)
WHERE ' + #column + ' = ''' + CAST(#value AS VARCHAR(50)) + ''''
print #sql
EXEC sp_executesql #Sql
FETCH NEXT FROM table_cursor
INTO #table, #column;
END
CLOSE table_cursor
DEALLOCATE table_cursor