programmatically generate script for a table - sql-server

I learned how to generate script for a table.
Eg for this table:
to generate script like this (I omitted something):
CREATE TABLE [dbo].[singer_and_album](
[singer] [varchar](50) NULL,
[album_title] [varchar](100) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[test_double_quote] ([singer], [album_title]) VALUES (N'Adale', N'19')
GO
INSERT [dbo].[test_double_quote] ([singer], [album_title]) VALUES (N'Michael Jaskson', N'Thriller"')
GO
I tried programmatically generating the script using this shell code. And got error:
PS
SQLSERVER:\SQL\DESKTOP-KHTRJOJ\MSSQL\Databases\yzhang\Tables\dbo.test_double_quote>
C:\Users\yzhang\Documents\script_out_table.ps1 "DESKTOP-KHTRJOJ\MSSQL"
"yzhang" "dbo" "test_double_quote",
"C:\Users\yzhang\Documents\script_out.sql"
Multiple ambiguous overloads found for "EnumScript" and the argument
count: "1". At C:\Users\yzhang\Documents\script_out_table.ps1:41
char:16
+ foreach ($s in $scripter.EnumScript($tbl.Urn)) { write-host $s }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Anybody can help? I don't know much about shell.
btw is shell the only way to generate scripts? Can we do it with some sql code? Thank you--
FYI, see this for how to manually generate script. In my case (sql server 2016 management studio) it's like
right click the database name (not table name) -> Tasks -> Generate scripts
choose a table or all tables
click advanced and select schema and data

this is a sql script to genrate table script
declare #vsSQL varchar(8000)
declare #vsTableName varchar(50)
select #vsTableName = '_PRODUCT'--- Your Table Name here
select #vsSQL = 'CREATE TABLE ' + #vsTableName + char(10) + '(' + char(10)
select #vsSQL = #vsSQL + ' ' + sc.Name + ' ' +
st.Name +
case when st.Name in ('varchar','varchar','char','nchar') then '(' + cast(sc.Length as varchar) + ') ' else ' ' end +
case when sc.IsNullable = 1 then 'NULL' else 'NOT NULL' end + ',' + char(10)
from sysobjects so
join syscolumns sc on sc.id = so.id
join systypes st on st.xusertype = sc.xusertype
where so.name = #vsTableName
order by
sc.ColID
select substring(#vsSQL,1,len(#vsSQL) - 2) + char(10) + ')'
Edit: c# code
public string GetScript(string strConnectionString
, string strObject
, int ObjType)
{
string strScript = null;
int intCounter = 0;
if (ObjType != 0)
{
ObjSqlConnection = new SqlConnection(strConnectionString.Trim());
try
{
ObjDataSet = new DataSet();
ObjSqlCommand = new SqlCommand("exec sp_helptext
[" + strObject + "]", ObjSqlConnection);
ObjSqlDataAdapter = new SqlDataAdapter();
ObjSqlDataAdapter.SelectCommand = ObjSqlCommand;
ObjSqlDataAdapter.Fill(ObjDataSet);
foreach (DataRow ObjDataRow in ObjDataSet.Tables[0].Rows)
{
strScript += Convert.ToString(ObjDataSet.Tables[0].Rows[intCounter][0]);
intCounter++;
}
}
catch (Exception ex)
{
strScript = ex.Message.ToString();
}
finally
{
ObjSqlDataAdapter = null;
ObjSqlCommand = null;
ObjSqlConnection = null;
}
}
return strScript;
}
To create Insert script use this store procedure
IF EXISTS (SELECT * FROM dbo.sysobjects
WHERE id = OBJECT_ID(N'[dbo].[InsertGenerator]') AND OBJECTPROPERTY(id,N'IsProcedure') = 1)
DROP PROCEDURE [dbo].[InsertGenerator]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROC [dbo].[InsertGenerator]
(
#tableName varchar(100),
#KeyColumn1 varchar(100)='',
#KeyColumn2 varchar(100)=''
)
AS
-- Generating INSERT statements in SQL Server
-- to validate if record exists - supports 2 field Unique index
--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR
SELECT column_name,data_type FROM information_schema.columns WHERE table_name = #tableName
OPEN cursCol
DECLARE #string nvarchar(max) --for storing the first half of INSERT statement
DECLARE #stringData nvarchar(max) --for storing the data (VALUES) related statement
DECLARE #dataType nvarchar(1000) --data types returned for respective columns
DECLARE #FieldVal nvarchar(1000) -- save value for the current field
DECLARE #KeyVal nvarchar(1000) -- save value for the current field
DECLARE #KeyTest0 nvarchar(1000) -- used to test if key exists
DECLARE #KeyTest1 nvarchar(1000) -- used to test if key exists
DECLARE #KeyTest2 nvarchar(1000) -- used to test if key exists
SET #KeyTest0=''
IF #KeyColumn1<>''
SET #KeyTest0='IF not exists (Select * from '+#tableName
SET #KeyTest1=''
SET #KeyTest2=''
SET #string='INSERT '+#tableName+'('
SET #stringData=''
SET #FieldVal=''
SET #KeyVal=''
DECLARE #colName nvarchar(50)
FETCH NEXT FROM cursCol INTO #colName,#dataType
IF ##fetch_status<>0
begin
print 'Table '+#tableName+' not found, processing skipped.'
close curscol
deallocate curscol
return
END
WHILE ##FETCH_STATUS=0
BEGIN
IF #dataType in ('varchar','char','nchar','nvarchar')
BEGIN
SET #FieldVal=''''+'''+isnull('''''+'''''+'+#colName+'+'''''+''''',''NULL'')+'',''+'
SET #KeyVal='''+isnull('''''+'''''+'+#colName+'+'''''+''''',''NULL'')+'',''+'
SET #stringData=#stringData+#FieldVal
END
ELSE
if #dataType in ('text','ntext','xml') --if the datatype is text or something else
BEGIN
SET #FieldVal='''''''''+isnull(cast('+#colName+' as varchar(max)),'''')+'''''',''+'
SET #stringData=#stringData+#FieldVal
END
ELSE
IF #dataType = 'money' --because money doesn't get converted from varchar implicitly
BEGIN
SET #FieldVal='''convert(money,''''''+isnull(cast('+#colName+' as varchar(200)),''0.0000'')+''''''),''+'
SET #stringData=#stringData+#FieldVal
END
ELSE
IF #dataType='datetime'
BEGIN
SET #FieldVal='''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+',121)+'''''+''''',''NULL'')+'',121),''+'
SET #stringData=#stringData+#FieldVal
END
ELSE
IF #dataType='image'
BEGIN
SET #FieldVal='''''''''+isnull(cast(convert(varbinary,'+#colName+') as varchar(6)),''0'')+'''''',''+'
SET #stringData=#stringData+#FieldVal
END
ELSE --presuming the data type is int,bit,numeric,decimal
BEGIN
SET #FieldVal=''''+'''+isnull('''''+'''''+convert(varchar(200),'+#colName+')+'''''+''''',''NULL'')+'',''+'
SET #KeyVal='''+isnull('''''+'''''+convert(varchar(200),'+#colName+')+'''''+''''',''NULL'')+'',''+'
SET #stringData=#stringData+#FieldVal
END
--Build key test
IF #KeyColumn1=#colName
begin
SET #KeyTest1 = ' WHERE [' + #KeyColumn1 + ']='
SET #KeyTest1 = #KeyTest1+#KeyVal+']'
end
IF #KeyColumn2=#colName
begin
SET #KeyTest2 = ' AND [' + #KeyColumn2 + ']='
SET #KeyTest2 = #KeyTest2+#KeyVal+']'
end
SET #string=#string+'['+#colName+'],'
FETCH NEXT FROM cursCol INTO #colName,#dataType
END
DECLARE #Query nvarchar(max)
-- Build the test string to check if record exists
if #KeyTest0<>''
begin
if #Keycolumn1<>''
SET #KeyTest0 = #KeyTest0 + substring(#KeyTest1,0,len(#KeyTest1)-4)
if #Keycolumn2<>''
begin
SET #KeyTest0 = #KeyTest0 + ''''
SET #KeyTest0 = #KeyTest0 + substring(#KeyTest2,0,len(#KeyTest2)-4)
end
SET #KeyTest0 = #KeyTest0 + ''')'
SET #query ='SELECT '''+substring(#KeyTest0,0,len(#KeyTest0)) + ') '
end
else
SET #query ='SELECT '''+substring(#KeyTest0,0,len(#KeyTest0))
SET #query = #query + substring(#string,0,len(#string)) + ') '
SET #query = #query + 'VALUES(''+ ' + substring(#stringData,0,len(#stringData)-2)+'''+'')'' FROM '+#tableName
exec sp_executesql #query
CLOSE cursCol
DEALLOCATE cursCol
GO
and use of InsertGenerator like below
DECLARE #return_value int
EXEC #return_value = [dbo].[InsertGenerator]
#tableName = N'_PRODUCT'
SELECT 'Return Value' = #return_value

Related

An OLE DB error has occurred. Error code: 0x80040E14, Invalid column name

I have an ETL package built in SSIS that I'm trying to run but I'm getting this error, mainly the third one:
The part in the package that is giving the error is built like this:
The specific component that is causing the error is the call to the SP and this are the parameters:
The parameters are translated to:
The parameters come from the query done at the start of the data flow:
The error mentions invalid column 'P2' the only column that takes this value is SG_PLANO_CTB.
This is the SP that's being used:
USE [SISF_DW_REPORTING]
GO
/****** Object: StoredProcedure [dbo].[SP_INSERT_EAF_MEMBER] Script Date: 8/10/2018 11:22:07 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- Batch submitted through debugger: SQLQuery64.sql|7|0|C:\Users\SQL_AD~1.CMC\AppData\Local\Temp\3\~vs4CBB.sql
-- Batch submitted through debugger: SQLQuery29.sql|7|0|C:\Users\SQL_AD~1.CMC\AppData\Local\Temp\3\~vs8A81.sql
-- =============================================
-- Author:
-- Create date:
-- Description: This stored procedure creates the Early Arriving Fact for a given reference table
-- =============================================
ALTER PROCEDURE [dbo].[SP_INSERT_EAF_MEMBER]
#TABLE NVARCHAR(50)
,#CD_REF NVARCHAR(50)
,#LOG_ID INT
,#ID_SK_COMPOSITE NVARCHAR(50) = NULL
,#COL_SK_COMPOSITE NVARCHAR(50) = NULL
,#DT_LOAD_DATE INT = NULL
,#TABLE_FCT NVARCHAR(50) = NULL
,#DEBUG BIT = 0
AS
BEGIN
SET NOCOUNT ON
IF 1=2
BEGIN
SELECT CAST(NULL AS INT) AS ID_REF
,CAST(NULL AS NVARCHAR(50)) AS DS_TBL_NAME
,CAST(NULL AS NVARCHAR(50)) AS CD_SRCE_SYTM
,CAST(NULL AS INT) AS LOG_ID
,CAST(NULL AS INT) AS DT_LOAD_DATE
,CAST(NULL AS NVARCHAR(50)) AS DS_TBL_FCT_NAME
END
--****************************************************
SET #TABLE = LTRIM(RTRIM(#TABLE))
SET #CD_REF = LTRIM(RTRIM(#CD_REF))
SET #TABLE_FCT = LTRIM(RTRIM(#TABLE_FCT))
--****************************************************
DECLARE #ID_INT_EAF INT
DECLARE #ID_EAF NVARCHAR(100)
DECLARE #DS_EAF NVARCHAR(100)
DECLARE #DT_INT_EAF NVARCHAR(100)
DECLARE #DT_DAT_EAF NVARCHAR(100)
DECLARE #CD_INT_EAF NVARCHAR(100)
DECLARE #CD_VAR_EAF NVARCHAR(100)
DECLARE #FL_EAF NVARCHAR(4)
DECLARE #NR_INT_EAF NVARCHAR(100)
DECLARE #NR_VAR_EAF NVARCHAR(100)
DECLARE #QT_EAF NVARCHAR(100)
DECLARE #VL_EAF NVARCHAR(100)
DECLARE #DMS_EAF NVARCHAR(100)
DECLARE #GPS_EAF NVARCHAR(100)
DECLARE #WGS_EAF NVARCHAR(100)
DECLARE #DT_CRTN NVARCHAR(100)
DECLARE #QUERY_FCT_LOAD_EAF VARCHAR(7000)
DECLARE #QUERY_REF_EAF VARCHAR(7000)
DECLARE #SG_EAF NVARCHAR(100)
DECLARE #HR_EAF NVARCHAR(100)
SET #ID_EAF = '-1'
SET #DS_EAF = '''EAF Member ('+#CD_REF+')'''
SET #DT_INT_EAF = '-1'
SET #DT_DAT_EAF = '''1900-01-01'''
SET #CD_VAR_EAF = ''''+#CD_REF+''''
SET #CD_INT_EAF = '-1'
SET #FL_EAF = '''-1'''
SET #NR_INT_EAF = '0'
SET #NR_VAR_EAF = '''EAF Member'''
SET #QT_EAF = '''0'''
SET #VL_EAF = '''0'''
SET #DMS_EAF = '''EAF Member'''
SET #GPS_EAF = '''EAF Member'''
SET #WGS_EAF = '-1'
SET #DT_CRTN = CONVERT(NVARCHAR(8),GETDATE(),112)
SET #SG_EAF = '''EAF'''
SET #HR_EAF = '''00:00:00'''
-- Declare auxiliary variables
DECLARE #TABLE_NAME NVARCHAR(50), #COLUMN_NAME NVARCHAR(100), #EAF_VALUE NVARCHAR(100)
DECLARE #INSERT NVARCHAR(3000), #VALUES NVARCHAR(3000), #WHERE NVARCHAR(1000), #IDENTITY_ON NVARCHAR(1000), #IDENTITY_OFF NVARCHAR(1000)
DECLARE #STATEMENT VARCHAR(7000)
SET #IDENTITY_ON = 'SET IDENTITY_INSERT ' + #TABLE + ' ON;'
SET #IDENTITY_OFF = 'SET IDENTITY_INSERT ' + #TABLE + ' OFF;'
SET #INSERT = 'INSERT INTO ' + #TABLE + ' ('
SET #VALUES = ' SELECT '
BEGIN
IF #COL_SK_COMPOSITE IS NULL
SET #WHERE = ' WHERE NOT EXISTS (SELECT 1 FROM ' + #TABLE + ' WHERE CD_' + SUBSTRING(#TABLE,9,LEN(#TABLE)) + ' = '''+#CD_REF+''');'
ELSE
SET #WHERE = ' WHERE NOT EXISTS (SELECT 1 FROM ' + #TABLE + ' WHERE CD_' + SUBSTRING(#TABLE,9,LEN(#TABLE)) + ' = '''+#CD_REF+''' AND ' + #COL_SK_COMPOSITE + ' = ' + #ID_SK_COMPOSITE + ');'
END
DECLARE TABLE_COLUMNS CURSOR FOR
SELECT
C.TABLE_NAME
,C.COLUMN_NAME
,CASE
WHEN #COL_SK_COMPOSITE IS NOT NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'ID' AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,5,LEN(C.TABLE_NAME)) AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,9,LEN(C.TABLE_NAME))
THEN #ID_SK_COMPOSITE
WHEN #COL_SK_COMPOSITE IS NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'ID' AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,5,LEN(C.TABLE_NAME)) AND C.NEW_COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(C.TABLE_NAME,9,LEN(C.TABLE_NAME))
THEN #ID_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'DS'
THEN #DS_EAF
WHEN C.NEW_COLUMN_NAME = 'DT_START' THEN '''1900-01-01'''
WHEN C.NEW_COLUMN_NAME = 'DT_END' THEN '''9999-12-31'''
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'DT' THEN
CASE
WHEN C.NEW_COLUMN_NAME LIKE 'DT_CRTN' THEN #DT_CRTN
WHEN C.DATA_TYPE LIKE 'int' THEN #DT_INT_EAF
ELSE #DT_DAT_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'CD' THEN
CASE WHEN C.DATA_TYPE LIKE 'int' THEN #CD_INT_EAF ELSE #CD_VAR_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'FL'
THEN #FL_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'NR' THEN
CASE
WHEN C.DATA_TYPE LIKE 'int' THEN #NR_INT_EAF
WHEN C.DATA_TYPE LIKE 'numeric' THEN #NR_INT_EAF
ELSE #NR_VAR_EAF END
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'QT'
THEN #QT_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'VL'
THEN #VL_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'DMS'
THEN #DMS_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'GPS'
THEN #GPS_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,3) LIKE 'WGS'
THEN #WGS_EAF
WHEN C.NEW_COLUMN_NAME = 'CTL_LOG_EAF'
THEN '1'
WHEN LEFT(C.NEW_COLUMN_NAME,7) LIKE 'CTL_LOG'
THEN CAST(#LOG_ID AS NVARCHAR(50))
WHEN #COL_SK_COMPOSITE IS NOT NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'SG'
THEN #ID_SK_COMPOSITE
WHEN #COL_SK_COMPOSITE IS NULL AND LEFT(C.NEW_COLUMN_NAME,2) LIKE 'SG'
THEN #SG_EAF
WHEN LEFT(C.NEW_COLUMN_NAME,2) LIKE 'HR'
THEN #HR_EAF
ELSE ''
END EAF_VALUE
FROM
(
SELECT
TABLE_NAME
,COLUMN_NAME
,CASE WHEN LEFT(COLUMN_NAME,2) LIKE 'X_' THEN SUBSTRING(COLUMN_NAME,3,LEN(COLUMN_NAME)) ELSE COLUMN_NAME END AS NEW_COLUMN_NAME
,DATA_TYPE
,ORDINAL_POSITION
FROM
INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME NOT LIKE 'ID_'+SUBSTRING(TABLE_NAME,9,LEN(TABLE_NAME))
) C
INNER JOIN
INFORMATION_SCHEMA.TABLES T
ON C.TABLE_NAME = T.TABLE_NAME
WHERE
T.TABLE_TYPE LIKE 'BASE TABLE'
AND T.TABLE_NAME LIKE #TABLE
ORDER BY
TABLE_NAME, ORDINAL_POSITION
OPEN TABLE_COLUMNS
FETCH NEXT FROM TABLE_COLUMNS INTO #TABLE_NAME, #COLUMN_NAME, #EAF_VALUE;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #COLUMN_NAME <> ''
BEGIN
SET #INSERT = #INSERT + #COLUMN_NAME + ', '
END
IF #EAF_VALUE <> ''
BEGIN
SET #VALUES = #VALUES + #EAF_VALUE + ', '
END
FETCH NEXT FROM TABLE_COLUMNS INTO #TABLE_NAME, #COLUMN_NAME, #EAF_VALUE;
END
CLOSE TABLE_COLUMNS
DEALLOCATE TABLE_COLUMNS
-- Final columns
SET #INSERT = LEFT(#INSERT,LEN(#INSERT)-1) + ')'
SET #VALUES = LEFT(#VALUES,LEN(#VALUES)-1)
SET #QUERY_FCT_LOAD_EAF = 'INSERT INTO FCT_LOAD_EAF (ID_LOAD_DATE, ID_CRTN_DATE, DS_REF_TABLE_NAME, DS_FCT_TABLE_NAME, CD_SRCE_SYTM,CTL_LOG_INSERT) SELECT '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+', '+#DT_CRTN+', '''+#TABLE+''', '''+#TABLE_FCT+''', '''+#CD_REF+''', '+CAST(#LOG_ID AS NVARCHAR(50))+' '+#WHERE
IF #DEBUG = 1 BEGIN SELECT #QUERY_FCT_LOAD_EAF END ELSE BEGIN EXECUTE(#QUERY_FCT_LOAD_EAF) END
PRINT #QUERY_FCT_LOAD_EAF
SET #STATEMENT = #INSERT + #VALUES + #WHERE
IF #DEBUG = 1 BEGIN SELECT #STATEMENT END ELSE BEGIN EXECUTE(#STATEMENT) END
PRINT #STATEMENT
IF LEFT(#TABLE,2) = 'X_'
BEGIN
SET #QUERY_REF_EAF = 'SELECT X_ID_'+SUBSTRING(#TABLE,7,LEN(#TABLE))+' AS ID_REF, ''' + #TABLE + ''' AS DS_TBL_NAME, CAST(X_CD_SRCE_SYTM AS NVARCHAR(50)) AS CD_SRCE_SYTM, '+CAST(#LOG_ID AS NVARCHAR(50))+' AS LOG_ID, '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+' AS DT_LOAD_DATE , ''' + #TABLE_FCT + ''' AS DS_TBL_FCT_NAME FROM '+#TABLE+' WHERE X_CD_SRCE_SYTM LIKE '''+#CD_REF+''''
IF #DEBUG = 1 BEGIN SELECT #QUERY_REF_EAF END ELSE BEGIN EXECUTE(#QUERY_REF_EAF) END
PRINT #QUERY_REF_EAF
END
ELSE
BEGIN
SET #QUERY_REF_EAF = 'SELECT ID_'+SUBSTRING(#TABLE,5,LEN(#TABLE))+' AS ID_REF, ''' + #TABLE + ''' AS DS_TBL_NAME, CAST(CD_SRCE_SYTM AS NVARCHAR(50)) AS CD_SRCE_SYTM, '+CAST(#LOG_ID AS NVARCHAR(50))+' AS LOG_ID, '+CAST(#DT_LOAD_DATE AS NVARCHAR(8))+' AS DT_LOAD_DATE, ''' + #TABLE_FCT + ''' AS DS_TBL_FCT_NAME FROM '+#TABLE+' WHERE CD_SRCE_SYTM LIKE '''+#CD_REF+''''
IF #DEBUG = 1 BEGIN SELECT #QUERY_REF_EAF END ELSE BEGIN EXECUTE(#QUERY_REF_EAF) END
PRINT #QUERY_REF_EAF
END
SET NOCOUNT OFF
END
I tried debugging the SP but I can't figure out where he builds the query that uses 'P2' as a column and not as value of the column SG_PLANO_CTB
Edit: I decided to log the parameters that were being used. Found out that the one causing the call causing the error is
exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, 'P2', 'SG_PLANO_CTB'
And the query that's causing the error is
INSERT INTO REF_FIN_RUBRICA (CD_RUBRICA, DS_RUBRICA, CD_KEY, CD_PARENT, SG_PLANO_CTB, DT_START, DT_END, CTL_LOG_UPDATE, CTL_LOG_EAF) SELECT '11.1.1', 'EAF Member (11.1.1)', '11.1.1', '11.1.1', P2, '1900-01-01', '9999-12-31', 210999, 1 WHERE NOT EXISTS (SELECT 1 FROM REF_FIN_RUBRICA WHERE CD_RUBRICA = '11.1.1' AND SG_PLANO_CTB = P2);
I would guess the string delimitators aren't being added in the cursor somewhere. Can't see where though.
I tried to step through your generated proc logically, and I think I see where the issue lies. The call that's causing the error, exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, 'P2', 'SG_PLANO_CTB' should probably be changed to:
exec SISF_DW_REPORTING..SP_INSERT_EAF_MEMBER 'REF_FIN_RUBRICA','11.1.1', 210999, '''P2''', 'SG_PLANO_CTB'
It looks like the dynamic sql generation takes the value of one of your input variables and uses that in the query string it builds. If your query needs a string value, you have to additionally double delimit it.

T-SQL context issue

I have created a script to compare the tables of two databases to find differences. I want to be able to manually set two variables (one for each database) and have the 'USE' statement use the variable value for one of the databases but it changes context and does work correctly.
This is what I am trying to use to populating a variable (#Use) with the USE code to execute
--set #Use = 'USE ' + #NewProdDB + ';SELECT name FROM sys.tables'
--EXEC (#Use)
This is the entire query:
--========================================================================================================
-- Used to find table values in the test upgrade system database not found the newly upgraded system
-- database. Make sure change the system database names before running the query.
-- Also, select the upgraded database to run against
--========================================================================================================
DECLARE #NewProdDB VARCHAR(100)
DECLARE #TestUpgradeDB VARCHAR(100)
DECLARE #Columns VARCHAR (MAX)
DECLARE #Query VARCHAR(MAX)
DECLARE #ResultsTest VARCHAR(MAX)
DECLARE #SetResultsCursor NVARCHAR(MAX)
DECLARE #Fetcher NVARCHAR(MAX)
DECLARE #Use NVARCHAR(50)
DECLARE #ListOfTables VARCHAR(100)
DECLARE #WTF NVARCHAR(max)
DECLARE #rescanCode nvarchar(max)
/* Enter Upgraded system DB here */
SET #NewProdDB = 'zSBSSYS'
/* Enter Test Upgrade system DB here */
SET #TestUpgradeDB = 'TESTzSBSSYS'
--set #Use = 'USE ' + #NewProdDB + ';SELECT name FROM sys.tables'
--EXEC (#Use)
SET NOCOUNT ON
set #rescanCode = 'DECLARE recscan CURSOR FOR
SELECT TABLE_NAME FROM ' + #TestUpgradeDB + '.INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME NOT LIKE ''Mbf%'' AND TABLE_TYPE = ''BASE TABLE''
ORDER BY TABLE_NAME'
exec (#rescanCode)
OPEN recscan
FETCH NEXT FROM recscan INTO #ListOfTables
WHILE ##fetch_status = 0
BEGIN
BEGIN TRY
/* START Table column query */
Declare #Table varchar(60)
set #Table = #ListOfTables
set #table = (SELECT top 1 name FROM sys.tables where name = #Table)
DECLARE
#sql1 nvarchar(max) = ''
,#INTOColumns NVARCHAR(MAX)=''
,#Where nvarchar(max) = ''
,#ColumnID Int
,#Column Varchar(8000)
,#Type Varchar(8000)
,#Length Int
,#del1 varchar(2) = ','
,#CRLF bit = 1
,#aliasfield varchar(5) = '[a].'
DECLARE CSR_Attributes CURSOR FOR
SELECT
[ColumnID] = Col.column_id,
[Column] = Col.Name,
[Type] = [types].name,
[Length] = Col.max_length
FROM sys.objects Obj, sys.columns Col, sys.types [types]
WHERE Obj.OBJECT_ID = Col.OBJECT_ID AND Obj.TYPE = 'U'
AND Col.system_type_id = [types].system_type_id
AND Obj.name = #table
AND Col.name <> 'tstamp'
ORDER BY Obj.name, Col.column_id, Col.name
OPEN CSR_Attributes
FETCH NEXT FROM CSR_Attributes INTO #ColumnID, #Column, #Type, #Length
WHILE ##FETCH_STATUS = 0
BEGIN
set #sql1 += #column + #del1
set #Where += 'b.' + #column + '=a.' + #column + ' and '
set #INTOColumns += '#INTOcol,'
FETCH NEXT FROM CSR_Attributes INTO #ColumnID, #Column, #Type, #Length
END
CLOSE CSR_Attributes
DEALLOCATE CSR_Attributes
SET #Columns = SUBSTRING(#sql1,1,len(#sql1)-1) -- get rid of last comma
SET #Where = SUBSTRING(#Where,1,len(#Where)-4) -- get rid of last 'and'
SET #INTOColumns = SUBSTRING(#INTOColumns,1,len(#INTOColumns)-1) -- get rid of last comma
/* END Table column query */
/* Create SELECT statement here */
SET #ResultsTest='SELECT TOP 1 ' + #Columns + '
FROM ' + #TestUpgradeDB + '..' + #Table + ' A
WHERE NOT EXISTS
(SELECT ' + #Columns + '
FROM ' + #NewProdDB + '..' + #Table + ' B WHERE ' + #Where + ')'
SET #SetResultsCursor = 'DECLARE DataReturned CURSOR FOR ' + #ResultsTest
exec (#SetResultsCursor)
OPEN DataReturned
SET #Fetcher = 'DECLARE #INTOcol NVARCHAR(Max)
FETCH NEXT FROM DataReturned INTO ' + #INTOColumns
exec (#Fetcher)
if ##FETCH_STATUS = 0
begin
CLOSE DataReturned
DEALLOCATE DataReturned
SET #Query='SELECT ' + #Columns + '
FROM ' + #TestUpgradeDB + '..' + #Table + ' A WHERE NOT EXISTS
(SELECT ' + #Columns + ' FROM ' + #NewProdDB + '..' + #Table + ' B WHERE ' + #Where + ')'
select #Table
exec (#Query)
end
else
begin
CLOSE DataReturned
DEALLOCATE DataReturned
end
end try
begin catch
--SELECT ERROR_MESSAGE() AS ErrorMessage;
end catch
FETCH NEXT FROM recscan INTO #ListOfTables
end
CLOSE recscan
DEALLOCATE recscan
SET NOCOUNT OFF
You can't do this:
DECLARE #DB varchar(10) = 'beep';
DECLARE #USE varchar(50) = 'USE '+ #DB;
EXEC sp_sqlexec #USE;
SELECT blah FROM bloop
Database context is only used during the #USE sql, then reverts
You can do this:
DECLARE #DB varchar(10) = 'beep';
DECLARE #SQL varchar(50) = 'USE '+#DB+'; SELECT blah FROM bloop;'
EXEC sp_sqlexec #USE;
That aside, look into SQL Server Data Tools (SSDT)
It does exactly what it seems you are trying to do, schema and/or data compare between databases, and it's very easy to use.

Challenge with dynamic SQL

I have a procedure that generates dynamic SQL that creates an insert into statement while querying an excel spreadsheet.
The resulting print from the messages screen can be pasted into an ssms window and executes. When I try to execute the SQL from within the stored procedure I get a syntax error as follows:
'SELECT * into TestClient FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', 'Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;', [Sheet1$])'
Msg 102, Level 15, State 1, Line 15
Incorrect syntax near 'SELECT * into TestClient FROM OPENROWSET('.
Below is the entire stored procedure. I know the problem is in the ticks (within the SET blocks that create the dynamic SQL I just can't figure out where the missing ticks are.
Here is the proc:
USE [ETL]
GO
/****** Object: StoredProcedure [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2] Script Date: 12/19/2017 4:03:05 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[ImportExcelSheetForCustomerEmployeeUpdate2](#BatchID int)
as
--EXEC ImportExcelSheetForCustomerEmployeeUpdate 2
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
-- Jeffery Williams
-- 12/18/2017
DECLARE #FileID int
,#ETLFilename varchar(250)
,#ClientName varchar(100)
,#FileType varchar(5)
,#ColumnCount int
,#RowsToETL int
,#StatusID int
,#Processed bit = 0
,#Count int
,#SQL nvarchar(4000)
,#Sheetname varchar(50) = '[Sheet1$]'
,#CMDSQL as varchar(4000)
,#SQLCmd NVARCHAR(MAX)
SELECT *
FROM FilesToImport
BEGIN
SELECT #Count = count(*)
FROM FilesToImport
WHERE BatchID = #BatchID
AND StatusID = 1
END
PRINT 'Count of records to process: ' + cast(#Count as varchar)
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
-- Rename the file
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\' + #ETLFilename + ' ETLEmployeexls.xls'
exec master..xp_cmdshell #CMDSQL
--PRINT cast(#cmdsql as varchar(4000))
-- Ciode below generates our select. Need to add an INTO clause and create a staging table for each import. Prior to this step we need to rename the file.
SET #SQL = ''''
SET #SQL = #SQL + 'SELECT * into ' + coalesce(#ClientName, 'TestClient') + ' FROM OPENROWSET('
SET #SQL = #SQL + ''''
SET #SQL = #SQL + '''' + 'Microsoft.ACE.OLEDB.12.0' + '''' --+ ', '
-- Excel 12.0;HDR=NO;Database=g:\UnZip\ImportSampleXLSX.xlsx;' + ''
SET #SQL = #SQL + '''' + ', '
SET #SQL = #SQL + '''' + '''Excel 12.0;HDR=YES;Database=G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls;''' + '''' + ', ' + #Sheetname + ')'
SET #SQL = #SQL + ''''
PRINT cast(#SQL as varchar(8000))
EXEC sp_executesql #SQL
set #CMDSQL = 'rename G:\CustomerETL\Employee\PendingETL\ETLEmployeexls.xls ' + #ETLFilename
exec master..xp_cmdshell #CMDSQL
UPDATE FilesToImport
SET StatusID = 2
WHERE FileID = #FileID
/* -- TRUNCATE TABLE FilesToImport
UPDATE FilesToImport
SET StatusID = 1
*/
SET #Count = (#Count - 1)
CONTINUE
END
I am posting this as an answer but it should be comment. When I tried adding this as a comment StackOveflow kept thinking that I was trying to add #count as an email target.
In your code:
WHILE #Count > 0
BEGIN
BEGIN
SELECT TOP 1 #FileID = FileID, #ETLFilename = ETLFilename, #ClientName = ClientName
,#FileType = FileType, #ColumnCount = ColumnCount, #RowsToETL = RowsToETL
FROM FilesToImport
WHERE StatusID = 1
AND BatchID = #BatchID
END
you are not updating the value of #count. This will either never loop or loop forever. You probably want to add a statement (right before the end) such as this:
Set #count= ##rowcount;
Ben

DDL statements with variables for table and column names

In my stored procedure, I make a temp_tbl and want to add several columns in a cursor or while loop. All works fine the cursor (the creation of a temp_bl but I can´t add the column when the column string is in a varchar variable.
WHILE ##FETCH_STATUS = 0
BEGIN
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(10))
ALTER TABLE IVS.tmpBus
ADD #webadressenrow varchar(500) Null
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
The code above results in a syntax error, while this code works:
WHILE ##FETCH_STATUS = 0
BEGIN
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(10))
ALTER TABLE IVS.tmpBus
ADD SOMECOLUMNAME varchar(500) Null
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
Can anybody give me a syntax hint to this small problem?
You won't be able to parameterise the ALTER TABLE statement but you could build up the SQL and execute it something like this:
declare #sql nvarchar(max)
set #sql = 'create table IVS.tmpBus ( '
select
#sql = #sql + 'Webadresse_' +
row_number() over ( order by col ) +
' varchar(500) null, '
from sourceData
set #sql = substring(#sql, 1, len(#sql) - 2) + ' )'
exec #sql
Be careful about security/SQL-Injection attacks though.
Generally speaking DDL statements i.e. those that define tables and columns do not accept variables for table or column names.
You can sometimes get around that by preparing the statements but support for prepared DDL is not provided by all database engines.
The following example works in SQL Server 2005, although I would suggest that adding columns dynamically may not be the optimal solution
DECLARE #colname1 VARCHAR(10)
DECLARE #colname2 VARCHAR(10)
DECLARE #sql VARCHAR(MAX)
SET #colname1 = 'col1'
SET #colname2 = 'col2'
SET #sql = 'CREATE TABLE temptab (' + #colname1 + ' VARCHAR(10) )'
EXEC (#sql)
INSERT INTO temptab VALUES ('COl 1')
SET #sql = 'ALTER TABLE temptab ADD ' + #colname2 + ' VARCHAR(10)'
EXEC (#sql)
INSERT INTO temptab VALUES ('Col1', 'Col2')
SELECT * FROM temptab
DROP TABLE temptab
Produced the following results
col1 col2
---------- ----------
COl 1 NULL
Col1 Col2
i have Solved The Problem with the Non optimal Way.
The Code Works prefectly for me. i Hope another frustrated programmer can Use this.
DECLARE cur_web CURSOR FOR
SELECT IVS.LG_Webadressen.Adresse FROM IVS.LG_Webadressen WHERE IVS.LG_Webadressen.FK_GID = #welche
open cur_web /*Cursor wird geöffnet*/
fetch next from cur_web into #webadressen /*Erster Datensatz wird geholt*/
WHILE ##FETCH_STATUS = 0 /*Solange eine Datensatz vorhanden ist*/
BEGIN
/*Spalte Adden*/
SET #webadressenrow = 'Webadresse_'+CAST(#counter as nchar(1)) /*Anhängen des Durchlaufes an den Spaltennamen*/
SET #sql = 'ALTER TABLE IVS.temp_tbl ADD ' + #webadressenrow + ' VARCHAR(100)' /*Spalte adden*/
EXEC (#sql)
/*Wert für die Webadresse wird reingeschrieben*/
SET #sql = 'UPDATE IVS.temp_tbl Set ' + #webadressenrow + ' = ''' + #webadressen + ''' WHERE GID = ' + CAST(#welche as nchar(10)) + ''
EXEC(#sql)
/*nächtser Datensatz wird geholt*/
fetch next from cur_web into #webadressen
SET #counter = #counter + 1
END
/*Cursor zerstören und Schließen*/
CLOSE cur_web
DEALLOCATE cur_web

Select columns with NULL values only

How do I select all the columns in a table that only contain NULL values for all the rows? I'm using MS SQL Server 2005. I'm trying to find out which columns are not used in the table so I can delete them.
Here is the sql 2005 or later version: Replace ADDR_Address with your tablename.
declare #col varchar(255), #cmd varchar(max)
DECLARE getinfo cursor for
SELECT c.name FROM sys.tables t JOIN sys.columns c ON t.Object_ID = c.Object_ID
WHERE t.Name = 'ADDR_Address'
OPEN getinfo
FETCH NEXT FROM getinfo into #col
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #cmd = 'IF NOT EXISTS (SELECT top 1 * FROM ADDR_Address WHERE [' + #col + '] IS NOT NULL) BEGIN print ''' + #col + ''' end'
EXEC(#cmd)
FETCH NEXT FROM getinfo into #col
END
CLOSE getinfo
DEALLOCATE getinfo
SELECT cols
FROM table
WHERE cols IS NULL
This should give you a list of all columns in the table "Person" that has only NULL-values. You will get the results as multiple result-sets, which are either empty or contains the name of a single column. You need to replace "Person" in two places to use it with another table.
DECLARE crs CURSOR LOCAL FAST_FORWARD FOR SELECT name FROM syscolumns WHERE id=OBJECT_ID('Person')
OPEN crs
DECLARE #name sysname
FETCH NEXT FROM crs INTO #name
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('SELECT ''' + #name + ''' WHERE NOT EXISTS (SELECT * FROM Person WHERE ' + #name + ' IS NOT NULL)')
FETCH NEXT FROM crs INTO #name
END
CLOSE crs
DEALLOCATE crs
Or did you want to just see if a column only has NULL values (and, thus, is probably unused)?
Further clarification of the question might help.
EDIT:
Ok.. here's some really rough code to get you going...
SET NOCOUNT ON
DECLARE #TableName Varchar(100)
SET #TableName='YourTableName'
CREATE TABLE #NullColumns (ColumnName Varchar(100), OnlyNulls BIT)
INSERT INTO #NullColumns (ColumnName, OnlyNulls) SELECT c.name, 0 FROM syscolumns c INNER JOIN sysobjects o ON c.id = o.id AND o.name = #TableName AND o.xtype = 'U'
DECLARE #DynamicSQL AS Nvarchar(2000)
DECLARE #ColumnName Varchar(100)
DECLARE #RC INT
SELECT TOP 1 #ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
WHILE ##ROWCOUNT > 0
BEGIN
SET #RC=0
SET #DynamicSQL = 'SELECT TOP 1 1 As HasNonNulls FROM ' + #TableName + ' (nolock) WHERE ''' + #ColumnName + ''' IS NOT NULL'
EXEC sp_executesql #DynamicSQL
set #RC=##rowcount
IF #RC=1
BEGIN
SET #DynamicSQL = 'UPDATE #NullColumns SET OnlyNulls=1 WHERE ColumnName=''' + #ColumnName + ''''
EXEC sp_executesql #DynamicSQL
END
ELSE
BEGIN
SET #DynamicSQL = 'DELETE FROM #NullColumns WHERE ColumnName=''' + #ColumnName+ ''''
EXEC sp_executesql #DynamicSQL
END
SELECT TOP 1 #ColumnName = ColumnName FROM #NullColumns WHERE OnlyNulls=0
END
SELECT * FROM #NullColumns
DROP TABLE #NullColumns
SET NOCOUNT OFF
Yes, there are easier ways, but I have a meeting to go to right now. Good luck!
Here is an updated version of Bryan's query for 2008 and later. It uses INFORMATION_SCHEMA.COLUMNS, adds variables for the table schema and table name. The column data type was added to the output. Including the column data type helps when looking for a column of a particular data type. I didn't added the column widths or anything.
For output the RAISERROR ... WITH NOWAIT is used so text will display immediately instead of all at once (for the most part) at the end like PRINT does.
SET NOCOUNT ON;
DECLARE
#ColumnName sysname
,#DataType nvarchar(128)
,#cmd nvarchar(max)
,#TableSchema nvarchar(128) = 'dbo'
,#TableName sysname = 'TableName';
DECLARE getinfo CURSOR FOR
SELECT
c.COLUMN_NAME
,c.DATA_TYPE
FROM
INFORMATION_SCHEMA.COLUMNS AS c
WHERE
c.TABLE_SCHEMA = #TableSchema
AND c.TABLE_NAME = #TableName;
OPEN getinfo;
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = N'IF NOT EXISTS (SELECT * FROM ' + #TableSchema + N'.' + #TableName + N' WHERE [' + #ColumnName + N'] IS NOT NULL) RAISERROR(''' + #ColumnName + N' (' + #DataType + N')'', 0, 0) WITH NOWAIT;';
EXECUTE (#cmd);
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
END;
CLOSE getinfo;
DEALLOCATE getinfo;
You can do:
select
count(<columnName>)
from
<tableName>
If the count returns 0 that means that all rows in that column all NULL (or there is no rows at all in the table)
can be changed to
select
case(count(<columnName>)) when 0 then 'Nulls Only' else 'Some Values' end
from
<tableName>
If you want to automate it you can use system tables to iterate the column names in the table you are interested in
If you need to list all rows where all the column values are NULL, then i'd use the COLLATE function. This takes a list of values and returns the first non-null value. If you add all the column names to the list, then use IS NULL, you should get all the rows containing only nulls.
SELECT * FROM MyTable WHERE COLLATE(Col1, Col2, Col3, Col4......) IS NULL
You shouldn't really have any tables with ALL the columns null, as this means you don't have a primary key (not allowed to be null). Not having a primary key is something to be avoided; this breaks the first normal form.
Try this -
DECLARE #table VARCHAR(100) = 'dbo.table'
DECLARE #sql NVARCHAR(MAX) = ''
SELECT #sql = #sql + 'IF NOT EXISTS(SELECT 1 FROM ' + #table + ' WHERE ' + c.name + ' IS NOT NULL) PRINT ''' + c.name + ''''
FROM sys.objects o
JOIN sys.columns c ON o.[object_id] = c.[object_id]
WHERE o.[type] = 'U'
AND o.[object_id] = OBJECT_ID(#table)
AND c.is_nullable = 1
EXEC(#sql)
Not actually sure about 2005, but 2008 ate it:
USE [DATABASE_NAME] -- !
GO
DECLARE #SQL NVARCHAR(MAX)
DECLARE #TableName VARCHAR(255)
SET #TableName = 'TABLE_NAME' -- !
SELECT #SQL =
(
SELECT
CHAR(10)
+'DELETE FROM ['+t1.TABLE_CATALOG+'].['+t1.TABLE_SCHEMA+'].['+t1.TABLE_NAME+'] WHERE '
+(
SELECT
CASE t2.ORDINAL_POSITION
WHEN (SELECT MIN(t3.ORDINAL_POSITION) FROM INFORMATION_SCHEMA.COLUMNS t3 WHERE t3.TABLE_NAME=t2.TABLE_NAME) THEN ''
ELSE 'AND '
END
+'['+COLUMN_NAME+'] IS NULL' AS 'data()'
FROM INFORMATION_SCHEMA.COLUMNS t2 WHERE t2.TABLE_NAME=t1.TABLE_NAME FOR XML PATH('')
) AS 'data()'
FROM INFORMATION_SCHEMA.TABLES t1 WHERE t1.TABLE_NAME = #TableName FOR XML PATH('')
)
SELECT #SQL -- EXEC(#SQL)
Here I have created a script for any kind of SQL table. please copy this stored procedure and create this on your Environment and run this stored procedure with your Table.
exec [dbo].[SP_RemoveNullValues] 'Your_Table_Name'
stored procedure
GO
/****** Object: StoredProcedure [dbo].[SP_RemoveNullValues] Script Date: 09/09/2019 11:26:53 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- akila liyanaarachchi
Create procedure [dbo].[SP_RemoveNullValues](#PTableName Varchar(50) ) as
begin
DECLARE Cussor CURSOR FOR
SELECT COLUMN_NAME,TABLE_NAME,DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = #PTableName
OPEN Cussor;
Declare #ColumnName Varchar(50)
Declare #TableName Varchar(50)
Declare #DataType Varchar(50)
Declare #Flage int
FETCH NEXT FROM Cussor INTO #ColumnName,#TableName,#DataType
WHILE ##FETCH_STATUS = 0
BEGIN
set #Flage=0
If(#DataType in('bigint','numeric','bit','smallint','decimal','smallmoney','int','tinyint','money','float','real'))
begin
set #Flage=1
end
If(#DataType in('date','atetimeoffset','datetime2','smalldatetime','datetime','time'))
begin
set #Flage=2
end
If(#DataType in('char','varchar','text','nchar','nvarchar','ntext'))
begin
set #Flage=3
end
If(#DataType in('binary','varbinary'))
begin
set #Flage=4
end
DECLARE #SQL VARCHAR(MAX)
if (#Flage in(1,4))
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+']=0 where ['+#ColumnName+'] is null'
end
if (#Flage =3)
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+'] = '''' where ['+#ColumnName+'] is null '
end
if (#Flage =2)
begin
SET #SQL =' update ['+#TableName+'] set ['+#ColumnName+'] ='+'''1901-01-01 00:00:00.000'''+' where ['+#ColumnName+'] is null '
end
EXEC(#SQL)
FETCH NEXT FROM Cussor INTO #ColumnName,#TableName,#DataType
END
CLOSE Cussor
DEALLOCATE Cussor
END
You'll have to loop over the set of columns and check each one. You should be able to get a list of all columns with a DESCRIBE table command.
Pseudo-code:
foreach $column ($cols) {
query("SELECT count(*) FROM table WHERE $column IS NOT NULL")
if($result is zero) {
# $column contains only null values"
push #onlyNullColumns, $column;
} else {
# $column contains non-null values
}
}
return #onlyNullColumns;
I know this seems a little counterintuitive but SQL does not provide a native method of selecting columns, only rows.
I would also recommend to search for fields which all have the same value, not just NULL.
That is, for each column in each table do the query:
SELECT COUNT(DISTINCT field) FROM tableName
and concentrate on those which return 1 as a result.
SELECT t.column_name
FROM user_tab_columns t
WHERE t.nullable = 'Y' AND t.table_name = 'table name here' AND t.num_distinct = 0;
An updated version of 'user2466387' version, with an additional small test which can improve performance, because it's useless to test non nullable columns:
AND IS_NULLABLE = 'YES'
The full code:
SET NOCOUNT ON;
DECLARE
#ColumnName sysname
,#DataType nvarchar(128)
,#cmd nvarchar(max)
,#TableSchema nvarchar(128) = 'dbo'
,#TableName sysname = 'TableName';
DECLARE getinfo CURSOR FOR
SELECT
c.COLUMN_NAME
,c.DATA_TYPE
FROM
INFORMATION_SCHEMA.COLUMNS AS c
WHERE
c.TABLE_SCHEMA = #TableSchema
AND c.TABLE_NAME = #TableName
AND IS_NULLABLE = 'YES';
OPEN getinfo;
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = N'IF NOT EXISTS (SELECT * FROM ' + #TableSchema + N'.' + #TableName + N' WHERE [' + #ColumnName + N'] IS NOT NULL) RAISERROR(''' + #ColumnName + N' (' + #DataType + N')'', 0, 0) WITH NOWAIT;';
EXECUTE (#cmd);
FETCH NEXT FROM getinfo INTO #ColumnName, #DataType;
END;
CLOSE getinfo;
DEALLOCATE getinfo;
You might need to clarify a bit. What are you really trying to accomplish? If you really want to find out the column names that only contain null values, then you will have to loop through the scheama and do a dynamic query based on that.
I don't know which DBMS you are using, so I'll put some pseudo-code here.
for each col
begin
#cmd = 'if not exists (select * from tablename where ' + col + ' is not null begin print ' + col + ' end'
exec(#cmd)
end

Resources