I would like to create the stored procedure and generate insert statement for the table dynamically. The input parameters for the stored procedure are supposed to be schema, table name, #col1, #col2, ..., #colN. This stored procedure is supposed to take 1 random record from another server and based on this record is supposed to generate INSERT statement. #col1, #col2, ..., #colN parameters are optional in case you would like to overwrite original value with the one you need.
The insert record is supposed to look like that:
INSERT INTO schema_name.table_name VALUES (
col1,
col2,
...,
colN)
VALUES (
COALESCE(#col1, 'col1_value'),
COALESCE(#col2, 'col2_value'),
...,
COALESCE(#colN, 'colN_value')
);
Currently I can not realize how to take the real data and put it to the statement. What I already did is:
CREATE PROCEDURE dbo.GenerateSampleDataInsertSP
#SchemaName VARCHAR(255),
#TableName VARCHAR(255)
AS
SET NOCOUNT ON;
DECLARE #sql VARCHAR(MAX) = '',
#columns VARCHAR(MAX) = '',
#columnsWithCoalesce VARCHAR(MAX) = '';
SELECT c.name
INTO #column
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
JOIN sys.columns c ON c.object_id = t.object_id
JOIN sys.types tt ON c.system_type_id = tt.system_type_id
WHERE t.name = #TableName
AND s.name = #SchemaName
AND tt.name NOT IN ( 'timestamp' );
SET #columns = NULL;
SELECT #columns = ISNULL(#columns + ', ', '') + name
FROM #column;
SET #sql = 'SELECT TOP 1 ' + #columns + ' FROM AnotherDatabase.' + #SchemaName + '.' + #TableName + ' ORDER BY NEWID();';
SET #sql = 'INSERT INTO [' + #SchemaName + '].[' + #TableName + '] (' + #columns + ') VALUES ();';
SELECT #sql;
I do not care about ideal code or solution. I need result and that's it.
UPDATED:
-- Example #1
USE tempdb
GO
/*CREATE PROCEDURE dbo.GenerateSampleDataInsertSP ...*/
CREATE TABLE dbo.Employee (ID INT, EmployeeName VARCHAR(255));
INSERT INTO dbo.Employee VALUES (1, 'John Smith');
EXEC dbo.GenerateSampleDataInsertSP #SchemaName = 'dbo', #TableName = 'Employees';
------------------------ EXPECTED OUTPUT OF THE PROCEDURE (NOT THE ACTION, BUT PLAIN TEXT) ------------------
INSERT INTO dbo.Employee
(
ID,
EmployeeName
)
VALUES
(
COALESCE(#ID, '1'),
COALESCE(#EmployeeName, 'John Smith')
);
-- Example #2
USE tempdb
GO
/*CREATE PROCEDURE dbo.GenerateSampleDataInsertSP ...*/
CREATE TABLE dbo.Orders (ID INT, OrderNbr VARCHAR(10), OrderDate DATE, CustomerID ID);
INSERT INTO dbo.Orders VALUES (7, '12345678', GETDATE(), 1024);
EXEC dbo.GenerateSampleDataInsertSP #SchemaName = 'dbo', #TableName = 'Orders';
------------------------ EXPECTED OUTPUT OF THE PROCEDURE (NOT THE ACTION, BUT PLAIN TEXT) ------------------
INSERT INTO dbo.Orders
(
ID,
OrderNbr,
OrderDate,
CustomerId
)
VALUES
(
COALESCE(#ID, '7'),
COALESCE(#OrderNbr,'12345678'),
COALESCE(#OrderDate, '2015-07-05'),
COALESCE(#CustomerId, '1024')
);
Ok, I'll answer my own question. As I said that I do not care about the code beauty and performance, I just need the result so anyone who would provide more elegant solution would be accepted as solved solution. Here is the code:
CREATE PROCEDURE dbo.GenerateSampleDataInsertSP
#SchemaName VARCHAR(255),
#TableName VARCHAR(255)
AS
SET NOCOUNT ON;
IF EXISTS ( SELECT name
FROM tempdb.sys.tables
WHERE name LIKE '%##record%' )
BEGIN
DROP TABLE ##record;
END;
DECLARE #sql VARCHAR(MAX) = '',
#columns VARCHAR(MAX) = '',
#columnsWithCoalesce VARCHAR(MAX) = '';
SELECT c.name
INTO #column
FROM sys.tables t
JOIN sys.schemas s ON s.schema_id = t.schema_id
JOIN sys.columns c ON c.object_id = t.object_id
JOIN sys.types tt ON c.system_type_id = tt.system_type_id
WHERE t.name = #TableName
AND s.name = #SchemaName
AND tt.name NOT IN ( 'timestamp' );
SET #columns = NULL;
SELECT #columns = ISNULL(#columns + ', ', '') + name
FROM #column;
SET #sql = 'SELECT TOP 1 ' + #columns + ' INTO ##record FROM AnotherDataBase.' + #SchemaName + '.' + #TableName + ' ORDER BY NEWID();';
EXEC (#sql);
SET #sql = 'INSERT INTO [' + #SchemaName + '].[' + #TableName + '] (' + #columns + ') VALUES (';
DECLARE #columnsCur CURSOR, #ColumnName VARCHAR(255), #tmpValue VARCHAR(MAX), #sqlCommand nvarchar(1000);
SET #columnsCur = CURSOR FOR
SELECT name
FROM #column;
OPEN #columnsCur;
FETCH NEXT
FROM #columnsCur INTO #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #sqlCommand = 'SELECT #value=CAST(' + #ColumnName + ' AS VARCHAR(MAX)) FROM ##record;'
EXECUTE sp_executesql #sqlCommand, N'#value VARCHAR(MAX) OUTPUT', #value=#tmpValue OUTPUT
SET #sql = #sql + 'COALESCE(#'+ #ColumnName +', ''' + #tmpValue + '''),';
FETCH NEXT
FROM #columnsCur INTO #ColumnName;
END;
CLOSE #columnsCur;
DEALLOCATE #columnsCur;
SET #sql = #sql + ');'
SET #sql = REPLACE(#sql, ',);', ');');
SELECT #sql;
GO
Related
I want to write a function that counts non null and non empty entries of a field. My problem is that the query does not run since the #tableName variable is not recognized in the select statement and I do not know why
create function dbo.getCount(#cod int, #columnName as varchar(20), #tableName as varchar(20))
Returns int as
Begin
--Count all filled entries
Return (select COUNT(*) from #tableName
where #columnName <> '' and #columnName is not null)
End;
go
As mentioned in the comments, but to reiterate, as I'll delete them after this answer:
You can't do this with a function, for multiple reasons. SELECT
COUNT(*) FROM #TableName means count the number of rows in the
table variable #TableName not the table who's name is the value of #TableName. WHERE #ColumnName <> '' would mean where the value of the scalar variable doesn't have the value '',
not where the column (in the aforementioned table) with the name of value of #ColumnName doesn't have the value ''.
And you can't do this in a function as to do this type of thing, you
need dynamic SQL; and you can't use dynamic SQL in a function (as you
can't use the EXEC command).
You can, however, do this with a Stored Procedure:
CREATE PROC dbo.GetCount #SchemaName sysname = N'dbo', #TableName sysname, #ColumnName sysname, #Count int OUTPUT AS
BEGIN
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SELECT #SQL = N'SELECT #Count = COUNT(NULLIF(' + QUOTENAME(c.[name]) + N',''''))' + #CRLF +
N'FROM ' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.[name]) + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
JOIN sys.columns c ON t.object_id = c.object_id
WHERE s.[name] = #SchemaName
AND t.[name] = #TableName
AND c.[name] = #ColumnName;
--PRINT #SQL; --Your debugging friend
EXEC sp_executesql #SQL, N'#Count int OUTPUT', #Count OUTPUT;
END
GO
And you run the SP like below (with sample table):
CREATE TABLE dbo.TestTable (SomeColumn varchar(10));
INSERT INTO dbo.TestTable (SomeColumn)
VALUES(''),('abc'),(NULL);
GO
DECLARE #Count int;
EXEC dbo.GetCount #TableName = N'TestTable', #ColumnName = N'SomeColumn', #Count = #Count OUTPUT;
SELECT #Count; --Returns 1
GO
DB<>Fiddle
I am trying to write a stored procedure that will check a table if there are any null values in the table at all. I want this to be able to be called on any table that I ask it to. I'm having a hard time wit the code if anyone could help me please.
Create Procedure NullCheck
#table VarChar(128)
as
Begin
Declare #query Varchar(Max)
set #query = N'WITH xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' AS ns)
SELECT *
FROM' + QUOTENAME(#table) + 'AS T1
WHERE (
SELECT T1.*
FOR XML PATH' + '('row')' +', ELEMENTS XSINIL, TYPE
).exist' + '(' + '//*/#ns:nil'+ ')' + '= 1'
EXEC #query
END
Try this:
DECLARE #TableName NVARCHAR(128) = '[dbo].[SurveyInstances]'; -- or SYSNAME
DECLARE #DynamicSQLStatement NVARCHAR(MAX);
SET #DynamicSQLStatement = 'SELECT * FROM ' + #TableName + ' WHERE ' +
STUFF
(
(
SELECT ' OR [' + [name] + '] IS NULL'
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID(#TableName)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,3
,''
);
EXEC sp_executesql #DynamicSQLStatement;
IF EXISTS (SELECT 1 FROM [sys].[objects] WHERE [object_id] = OBJECT_ID(N'[dbo].[usp_GetRowsWithAtLeastOneNULLvalue') AND [type] IN (N'P', N'PC'))
BEGIN
DROP PROCEDURE [dbo].[usp_GetRowsWithAtLeastOneNULLvalue];
END;
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[usp_GetRowsWithAtLeastOneNULLvalue]
(
#TableName NVARCHAR(128)
)
AS
BEGIN;
DECLARE #DynamicSQLStatement NVARCHAR(MAX);
SET #DynamicSQLStatement = 'SELECT * FROM ' + #TableName + ' WHERE ' +
STUFF
(
(
SELECT ' OR [' + [name] + '] IS NULL'
FROM [sys].[columns]
WHERE [object_id] = OBJECT_ID(#TableName)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1
,3
,''
);
EXEC sp_executesql #DynamicSQLStatement;
END;
Here's my answer. This only checks columns that are nullable:
--/*
create procedure dbo.test_nullCheck (#SchemaName nvarchar(128), #TableName nvarchar(128)) as
begin
--declare #SchemaName nvarchar(128);
--declare #TableName nvarchar(128);
set #SchemaName = isnull(#SchemaName,'dbo')
--set #TableName = '';
declare #sql nvarchar(max);
declare #select nvarchar(max);
declare #from nvarchar(max);
declare #where nvarchar(max);
select #select = 'select * ';
select #from = ' from '+quotename(s.name)+'.'+quotename(o.name)+' '
from sys.objects as o
inner join sys.schemas as s on o.schema_id=s.schema_id
and o.is_ms_shipped = 0
and o.type = 'U'
and o.name = #TableName
and s.name = #SchemaName
select #where = 'where '+
stuff((
select ' or '+quotename(c.name)+' is null'
from sys.columns as c
inner join sys.objects as o on c.object_id = o.object_id
and o.is_ms_shipped = 0
and c.is_nullable = 1
and o.type = 'U'
and o.name = #TableName
inner join sys.schemas as s on o.schema_id=s.schema_id
and s.name = #SchemaName
order by c.column_id
for xml path (''), type).value('.','nvarchar(max)')
, 1,4,'')+ ';'
set #sql = #select + #from + #where
print #sql
if #sql is not null
begin
exec sp_executesql #sql
end;
end;
--*/
exec dbo.test_NullCheck #schemaname = null, #tablename = 'Calendar'
-- does nothing in my database because the schema is ref
exec dbo.test_NullCheck #schemaname = 'ref', #tablename = 'Calendar'
-- returns rows with nulls
exec dbo.test_NullCheck #schemaname = 'ref', #tablename = 'Calendar; Drop Table Calendar; select * from Calendar'
-- does nothing because there isn't a table name like that
I have a table named a. Some cells containing a string 'Empty' in many columns. I want to find this columns. Can you help me?.
Try this dynamic query, it will check all the columns with character data and list the columns which has the word 'Empty'.
DECLARE #SearchText VARCHAR(50) = 'Empty'
DECLARE #sql NVARCHAR(MAX) = 'SELECT '
SELECT #sql = #sql + 'MAX(CASE WHEN ' + c.COLUMN_NAME + ' LIKE ''%'+ #SearchText +'%'' THEN ''' + c.COLUMN_NAME +''' ELSE '''' END) + '','' + '
FROM INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_SCHEMA = 'dbo' and c.TABLE_NAME = 'a'
AND c.DATA_TYPE IN ('varchar','char','nvarchar','nchar','sysname')
SET #sql = #sql + ''''' FROM dbo.a'
EXEC sys.sp_executesql #sql
Hope this helps
Use the LIKE operator:
SELECT a.*
FROM a
WHERE a.col1 LIKE '%Empty%' OR a.col2 LIKE '%Empty%' OR ...
In sql server you can get object id of table then using that object id you can fetch columns. In that case it will be as below:
Step 1: First get Object Id of table
select * from sys.tables order by name
Step 2: Now get columns of your table and search in it:
select * from a where 'Empty' in (select name from sys.columns where object_id =1977058079)
Note: object_id is what you get fetch in first step for you relevant table
You can do it using unpivot with an help of dynamic query , here i have done below an working sample for you , there might be some modification you might have to do to put the below psedo code with your working .
Sample table structure been used :
create table ColTest
(
name1 varchar(10),
name2 varchar(10),
name3 varchar(10),
name4 varchar(10)
)
insert into ColTest values ('sdas','asdasda','ewrewr','erefds')
insert into ColTest values ('sdas','asdasda','EMPTY','erefds')
insert into ColTest values ('EMPTY','asdasda','ewrewr','erefds')
DECLARE #table_name SYSNAME
SELECT #table_name = 'ColTest'
DECLARE #tmpTable SYSNAME
SELECT #tmpTable = 'ColTest2'
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = '
SELECT * into
' + #tmpTable + '
FROM ' + #table_name + '
UNPIVOT (
cell_value FOR column_name IN (
' + STUFF((
SELECT ', [' + c.name + ']'
FROM sys.columns c WITH(NOLOCK)
LEFT JOIN (
SELECT i.[object_id], i.column_id
FROM sys.index_columns i WITH(NOLOCK)
WHERE i.index_id = 1
) i ON c.[object_id] = i.[object_id] AND c.column_id = i.column_id
WHERE c.[object_id] = OBJECT_ID(#table_name)
AND i.[object_id] IS NULL
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + '
)
) unpiv'
PRINT #SQL
EXEC sys.sp_executesql #SQL
select * from ColTest2 where cell_value = 'EMPTY'
I'd suggest dynamic SQL
--First you set the variable #TableName to your actual table's name.
DECLARE #TableName VARCHAR(100)='a';
--The following statement will create a list of all columns with a data type containing the word "char" (others should not hold the value Empty)
DECLARE #ColList VARCHAR(MAX)=
STUFF(
(
SELECT ' OR ' + COLUMN_NAME + ' LIKE ''%empty%'''
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME=#TableName AND DATA_TYPE LIKE '%char%'
FOR XML PATH('')
),1,4,'');
--This statement builds a command
DECLARE #cmd VARCHAR(MAX)=
(
SELECT 'SELECT * FROM [' + #TableName + '] WHERE ' + #ColList
);
--Here you can see the command
PRINT #cmd;
--And here it is executed
EXEC(#cmd);
I want to write SP to delete rows from given table based on ID column. I tried the following:
CREATE PROCEDURE dbo.delResTab #schema VARCHAR(20), #table VARCHAR(50), #tableID int
AS
DECLARE #column VARCHAR(50) = (
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.columns
WHERE TABLE_SCHEMA = #schema
AND TABLE_NAME = #table
AND ORDINAL_POSITION = 1
)
DELETE FROM #schema + '.' + #table WHERE #column >= #tableId
but this does not work obviously. Any advice?
I want to be able to run
exec dbo.delResTab #schema = 'dbo', #table = 'test', #tableID = 3
CREATE PROCEDURE dbo.delResTab
(
#schema SYSNAME,
#table SYSNAME,
#tableID INT
)
AS BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX)
SELECT #SQL = '
DELETE FROM [' + #schema + '].[' + #table + ']
WHERE ' + c.name + ' >= ' + CAST(#tableID AS NVARCHAR(10))
FROM sys.columns c
WHERE c.is_identity = 1
AND c.[object_id] = OBJECT_ID(#schema + '.' + #table)
--PRINT #SQL
EXEC sys.sp_executesql #SQL
END
Does anybody know of a proc or script which will generate any row into an insert statement into the same table?
Basically, I'd like to call something like
exec RowToInsertStatement 'dbo.user', 45;
And the following code would be output
insert into dbo.MyTable( FirstName, LastName, Position)
values( 'John', 'MacIntyre', 'Software Consultant');
I realize I could
insert into dbo.MyTable
select * from dbo.MyTable where id=45;
But this obviously won't work, because the ID column will complain (I hope it complains) and there's no way to just override that one column without listing all columns, and in some tables there could be hundreds.
So, does anybody know of a proc that will write this simple insert for me?
EDIT 3:04: The purpose of this is so I can make a copy of the row, so after the INSERT is generated, I can modify it into something like
insert into dbo.MyTable( FirstName, LastName, Position)
values( 'Dave', 'Smith', 'Software Consultant');
.. no obviously this contrived example is so simple it doesn't make sense, but if you have a table with 60 columns, and all you need is to change 3 or 4 values, then it starts to be a hassle.
Does that make sense?
Update
I believe the following dynamic query is what you want:
declare #tableName varchar(100), #id int, #columns varchar(max), #pk varchar(20)
set #tableName = 'MyTable'
set #pk = 'id'
set #id = 45
set #columns = stuff((select ',['+c.name+']' [text()] from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
print 'insert into [' + #tableName + '] (' + #columns + ')
select ' + #columns + '
from [' + #tableName + ']
where ' + #pk + ' = ' + cast(#id as varchar)
Update 2
The actual thing that you wanted:
declare #tableName varchar(100), #id int, #columns nvarchar(max), #pk nvarchar(20), #columnValues nvarchar(max)
set #tableName = 'MyTable'
set #pk = 'id'
set #id = 45
set #columns = stuff((select ',['+c.name+']' [text()] from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
set #columnValues = 'set #actualColumnValues = (select' +
stuff((select ','','''''' + cast(['+c.name+'] as varchar(max)) + '''''''' [text()]' [text()]
from sys.tables t
join sys.columns c on t.object_id = c.object_id
where t.name = #tableName and c.name <> #pk for xml path('')),1,1,'')
+ 'from [' + #tableName + ']
where ' + #pk + ' = ' + cast(#id as varchar)
+ 'for xml path(''''))'
--select #columnValues
declare #actualColumnValues nvarchar(max), #columnValuesParams nvarchar(500)
SET #columnValuesParams = N'#actualColumnValues nvarchar(max) OUTPUT';
EXECUTE sp_executesql #columnValues, #columnValuesParams, #actualColumnValues OUTPUT;
--SELECT stuff(#actualColumnValues, 1,1, '')
declare #statement nvarchar(max)
set #statement =
'insert into [' + #tableName + '] (' + #columns + ')
select ' + stuff(#actualColumnValues,1,1,'')
print #statement
What it does is this:
It generates the insert statement and then it queries the actual data from the table and generates the select statement with that data. May not work correctly for some really complex datatypes but for varchars, datetimes and ints should work like a charm.
This stored proc works great for me:
http://vyaskn.tripod.com/code.htm#inserts
Did you know that in Enterprise Manager and SQL Server Management Studio that you can, from the object browser, drag the list of columns into the text window and it will drop the names of all the columns into the text, separated by commas?