Is it possible to search for records in Microsoft SQL Server manager?
I mean something like in VS pressing Ctrl-F and searching by word?
There is no way in searching for objects in SQL Server management studio. There are views and tables that can be used to search for objects like:
SELECT * FROM sys.tables WHERE name LIKE '%...%'
To search for tables.
If you mean, searching for data within a table, I need to learn T-SQL.
There are non-free 3rd party tools (ex. Redgate's SQL Search), but I use the proc below. You have to create the proc in every [master] database so it's available server-wide, but you can pass in a search term and an optional database name (otherwise it searches through object definitions in all databases):
USE [master]
GO
/****** Object: StoredProcedure [dbo].[sp_FindTextOnServer] Script Date: 10/6/2017 3:39:19 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*-----------------------------------------------------------
This procedure will search all or a specified database objects
for the supplied text and return a table with the values
Examples:
EXEC sp_FindTextOnServer 'Billing', 'fcsCore'
EXEC sp_FindTextOnServer 'vJurisdiction'
-----------------------------------------------------------*/
ALTER PROCEDURE [dbo].[sp_FindTextOnServer]
#text VARCHAR(40),
#searchDB VARCHAR(100) = NULL
AS
DECLARE #DisplayText VARCHAR(100),
#sSql VARCHAR(1000),
#line VARCHAR(300),
#char CHAR,
#lineNo INTEGER,
#counter INTEGER,
#AddedRecord BIT,
#dbObjectType VARCHAR(100),
#dbObject VARCHAR(100),
#ObjectBody VARCHAR(7000),
#dbName VARCHAR(100)
SET #DisplayText = #Text
SET #text = '%' + #text + '%'
SET #AddedRecord = 0
CREATE TABLE #SearchResults
(
DBName VARCHAR(100) NOT NULL,
ObjectType VARCHAR(100) NOT NULL,
ObjectName VARCHAR(100) NOT NULL,
Line INT NOT NULL,
Reference VARCHAR(7000) NOT NULL
)
CREATE TABLE #tempSysComments
(
DBName VARCHAR(100),
DBObjectType VARCHAR(100),
DBObject VARCHAR(100),
TextString text
)
--Populate a table with the search results from all databases on the server that include the searched text
SET #sSql = 'USE [?]
SELECT
''?'' AS DBName,
LOWER(REPLACE(o.type_desc, ''_'', '' '')) + '' ('' + RTRIM(type) + '')'' AS DBObjectType,
OBJECT_NAME(sm.object_id) AS DBObject,
CAST(sm.definition AS VARCHAR(7000)) AS TextString
FROM sys.sql_modules AS sm
JOIN sys.objects AS o
ON sm.object_id = o.object_id
WHERE CAST(sm.definition AS VARCHAR(7000)) LIKE ''' + #text + '''
ORDER BY o.type_desc, OBJECT_NAME(sm.object_id)'
IF (#searchDB IS NULL)
BEGIN
INSERT INTO #tempSysComments
EXEC sp_MSFOREachDB #sSql
END
ELSE
BEGIN
SET #sSql = REPLACE(#sSql, '?', #searchDB)
INSERT INTO #tempSysComments
EXEC (#sSql)
END
DECLARE codeCursor CURSOR
FOR
SELECT DBName, DBObjectType, DBObject, TextString
FROM #tempSysComments
WHERE DBName IS NOT NULL
OPEN codeCursor
FETCH NEXT FROM codeCursor INTO #dbName, #dbObjectType, #dbObject, #ObjectBody
IF ##FETCH_STATUS <> 0
BEGIN
PRINT 'Text ''' + #DisplayText + ''' was not found in objects on server ' + ##SERVERNAME
-- Close and release code cursor.
CLOSE codeCursor
DEALLOCATE codeCursor
RETURN
END
-- Search each object within code cursor.
WHILE ##FETCH_STATUS = 0
BEGIN
SET #lineNo = 0
SET #counter = 1
-- Process each line.
WHILE (#counter <> Len(#ObjectBody))
BEGIN
SET #char = SUBSTRING(#ObjectBody, #counter,1)
-- Check for line breaks.
IF (#char = CHAR(13))
BEGIN
SET #lineNo = #lineNo + 1
-- Check if we found the specified text.
IF (PATINDEX(#text, #line) <> 0)
BEGIN
SET #AddedRecord = 1
INSERT #SearchResults
SELECT #dbName, #dbObjectType, #dbObject, #lineNo, LEFT(RTRIM(LTRIM(#line)), 7000)
END
SET #line = ''
END
SET #line = #line + #char
SET #counter = #counter + 1
END
IF (#AddedRecord = 0)
INSERT #SearchResults
SELECT #dbName, #dbObjectType, #dbObject, 0, SUBSTRING(#ObjectBody, 1, 7000)
SET #AddedRecord = 0
FETCH NEXT FROM codeCursor INTO #dbName, #dbObjectType, #dbObject, #ObjectBody
END
-- Close and release cursor.
CLOSE codeCursor
DEALLOCATE codeCursor
-- Return the info.
SELECT DISTINCT DBName, ObjectType, ObjectName, Line, RTRIM(LTRIM(REPLACE(REPLACE(Reference, CHAR(9), ' '), CHAR(13)+CHAR(10), ' '))) AS Reference
FROM #SearchResults
ORDER BY DBName, ObjectType, ObjectName, Line
-- Cleanup.
DROP TABLE #SearchResults
DROP TABLE #tempSysComments
RETURN
Related
I am having issue with working of Object_ID to detect if the table already exists.
It works fine the first iteration and allows to create the required tables properly.
But if executed again, it still thinks/sees that tables are not created and tries to create the table and then SQL Server gives the error that tables already exist.
SQL Server version 2008
Code
--Alter Proc spCreateCustomerChartTables
--As
Begin
Declare
#mycursorMARKET Cursor,
#mycursorCUSTOMER Cursor,
#MarketNameEnglish nchar(30),
#CustomerID nchar(10),
#DDate date,
#textdate as nchar(12),
#tableName nchar(100),
#sqlcmd as nvarchar(500)
Set #DDate = GETDATE()
Set #mycursorMARKET = Cursor for Select Distinct MarketNameEnglish From dbo.tableMarketName Order by MarketNameEnglish ASC
Open #mycursorMARKET
Fetch Next From #mycursorMARKET Into #MarketNameEnglish
While ##FETCH_STATUS = 0
Begin
Set #mycursorCUSTOMER = Cursor for Select Distinct CustomerID From dbo.CustomerEmployeeDetail Order by CustomerID ASC
Open #mycursorCUSTOMER
Fetch Next From #mycursorCUSTOMER Into #CustomerID
While ##FETCH_STATUS =0
Begin
Set #textdate = cast(#DDate as NCHAR(12))
Set #tableName = RTrim(#MarketNameEnglish) + '_' + RTrim(#CustomerID) + '_' + RTrim(#textdate )
If OBJECT_ID(#tableName , 'U') IS Not Null
--IF Not EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
-- WHERE TABLE_NAME = #tableName )
Begin
Print 'Table Does Not Exist'
Set #sqlcmd = 'Select * Into ' + RTrim(#tableName) + ' From BlankChart'
Set #sqlcmd = RTRIM(#sqlcmd)
Set #sqlcmd = REPLACE (#sqlcmd, '-', '_')
Exec(#sqlcmd)
End
Else
Begin
Print 'Table Exists'
Set #sqlcmd = 'Drop Table ' + #tableName
Set #sqlcmd = RTRIM(#sqlcmd)
Set #sqlcmd = REPLACE (#sqlcmd, '-', '_')
Exec(#sqlcmd)
End
--Print #sqlcmd --Create chart tables here
Fetch Next From #mycursorCUSTOMER Into #CustomerID
End
--Print #MarketNameEnglish
Fetch Next From #mycursorMARKET Into #MarketNameEnglish
End
Close #mycursorMARKET
Deallocate #mycursorMARKET
Close #mycursorCUSTOMER
Deallocate #mycursorCUSTOMER
End
Your condition is "inverted":
your If OBJECT_ID(#tableName , 'U') IS Not Null should be changed to If OBJECT_ID(#tableName , 'U') IS Null
Finally found the mistake in my code. It had got nothing to do with Object_ID.
Actually the formating of variable #tablename was done incorrectly and at incorrect place. The dashes (-) of date in tablename were not replaced with underscore (_). This was causing the error.
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
Hi I need to create a view or stored procedure that combines data and returns a result set from 3 different databases on the same server using a column that holds a schema (db) name.
For Example on the first DB I have this table:
CREATE TABLE [dbo].[CloudUsers](
ID int IDENTITY(1,1) NOT NULL,
Username nvarchar(50) NULL,
MainDB nvarchar(100) NULL
) ON [PRIMARY]
Each CloudUser has a separate DB so next now I need to fetch the data from the User database using the MainDB name. The data I need is always 1 row cause I'm using aggregate functions / query.
So in the User MainDB let's say I have this table.
CREATE TABLE [dbo].[CLIENT](
ID int NOT NULL,
Name nvarchar(50) NULL,
ProjectDBName [nvarchar](100) NULL
CreationDate datetime NULL
) ON [PRIMARY]
And I query like:
select min(CreationDate) from MainDB.Client
The same Idea for the Client I need to fetch even more data from a 3rd database that points to the Client ProjectDBName. Again it's aggregate data:
select Count(id) as TotalTransactions from ProjectDBName.Journal
My final result should have records from all databases. It's readonly data that I need for statistics.
Final result set example:
CloudUsers.Username, MainDB->CreationDate, ProjectDBName->TotalTransaction
How can I achieve that ?
This is not easy - and without a schema and sample data, I can't give you a precise answer.
You need to iterate through each client, and use dynamic SQL to execute a the query against the mainDB and projectDB join. You can either do that in one gigantic "union" query, or by creating a temporary table and inserting the data into that temporary table, and then selecting from the temp table at the end of the query.
For you who are curious of how to solve this issue I have found my own solution using some cursors + dynamic and a simple table variable, enjoy.
ALTER PROCEDURE CloudAnalysis as
DECLARE #objcursor cursor
DECLARE #innercursor cursor
DECLARE #userid int
,#maindb nvarchar(100)
,#clientid int
,#name nvarchar(50)
,#projdb nvarchar(100)
,#stat nvarchar(50)
,#sql nvarchar(max)
,#vsql nvarchar(max)
,#rowcount int
DECLARE #result table(userid int,clientid int,maindb nvarchar(100),name nvarchar(50),projdb nvarchar(100),stat nvarchar(50))
SET #objcursor = CURSOR FORWARD_ONLY STATIC FOR SELECT c.id,c.maindb,u.client_id FROM dbo.ClientUsers c join dbo.UserClients u on c.id = u.user_id open #objcursor
FETCH NEXT FROM #objcursor INTO #userid,#maindb,#clientid
WHILE (##FETCH_STATUS=0)
BEGIN
IF (EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = #maindb
OR name = #maindb)))
BEGIN
set #sql = N'SELECT #name = c.name,#projdb=c.ProjectDBName FROM ' + #maindb + '.dbo.CLIENT c WHERE c.id = ' + cast(#clientid as nvarchar)
EXECUTE sp_executesql #sql, N'#name NVARCHAR(50) OUTPUT,#projdb NVARCHAR(100) OUTPUT',
#name = #name OUTPUT
,#projdb = #projdb OUTPUT
SELECT #rowcount = ##ROWCOUNT
IF #rowcount > 0
BEGIN
--print ' client: ' + cast(#clientid as nvarchar)+
--':' + #name + ' projdb: ' + #projdb
IF (EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = #projdb
OR name = #projdb)))
BEGIN
SET #sql = N'SELECT #stat = j.stat FROM ' + #projdb + '.dbo.JournalTransaction j'
EXECUTE sp_executesql #sql
,N'#stat NVARCHAR(50) OUTPUT'
,#stat = #stat OUTPUT
END
INSERT INTO #result (userid,clientid,maindb,name,projdb,stat)
VALUES (#userid,#clientid,#maindb,#name,#projdb,#stat)
END
END
FETCH NEXT FROM #objcursor INTO #userid,#maindb,#clientid
END
CLOSE #objcursor
DEALLOCATE #objcursor
SELECT * FROM #result
Is there any possibility to encrypt all existing stored procedures of a SQL Server 2008 database AFTER they have been created via an SQLCMD script?
The reason I want to do this is the following:
I'd like to develop the stored procedures without encryption so I can easily click on "Modify" in SQL Server Management Studio to check their contents.
However, for the deployment I'd like to encrypt them so I thought that maybe I could write a script which encrypts them only after they're created. For dev systems I simply wouldn't run the script while on end-user systems the script would be run.
You might want to check Encrypting all the Stored Procedures of a Database :
If you ever decide that you need to protect your SQL Stored
Procedures, and thought encrypting was a good idea, BE VERY CAREFUL!!!
Encrypting Database stored procedures SHOULD NOT be done without
having backup files or some sort of Source Control for the stored
procedures. The reason I say this is because, once they are encrypted,
there is no turning around. (Yes, there are third party tools that
will decrypt your code, but Why go through that trouble.)
This trick is something I developed because my company needed to host the application on a different server, and we were concerned
about our code being compromised. So, to deliver the database, we
decided to encrypt all out stored procedures. Having over a hundred
procedures written, I didn't want to open each procedure and paste
'WITH ENCRYPTION' in each and every stored procedure. (For those of
you who do not know how to encrypt, refer How Do I Protect My Stored
Procedure Code[^]). So I decided to make my own little C# application
that did the same.
This application is a console application made
using Visual Studio 2005 and SQL server 2005. The input parameters are
database name, Server address, database username and password. Once
you are able to provide these details, you are ready to have all your
stored procedures encrypted.
I have put the code of my application
here as is. For this code to work, you will need to add an
"Microsft.SQlserver.SMO" refrence to the application, so that the
classes such as "Database" and "StoredProcedure" are accessible.
BEFORE YOU DO THIS, TAKE A BACKUP!!!!!!!
//Connect to the local, default instance of SQL Server.
string DB = "";
ServerConnection objServerCOnnection = new ServerConnection();
objServerCOnnection.LoginSecure = false;
Console.WriteLine("Enter name or IP Address of the Database Server.");
objServerCOnnection.ServerInstance = Console.ReadLine();
Console.WriteLine("Enter name of the Database");
DB = Console.ReadLine();
Console.WriteLine("Enter user id");
objServerCOnnection.Login = Console.ReadLine();
Console.WriteLine("Enter Password");
objServerCOnnection.Password = Console.ReadLine();
Console.WriteLine(" ");
Server srv = new Server();
try // Check to see if server connection details are ok.
{
srv = new Server(objServerCOnnection);
if (srv == null)
{
Console.WriteLine("Server details entered are wrong,"
+ " Please restart the application");
Console.ReadLine();
System.Environment.Exit(System.Environment.ExitCode);
}
}
catch
{
Console.WriteLine("Server details entered are wrong,"
+ " Please restart the application");
Console.ReadLine();
System.Environment.Exit(System.Environment.ExitCode);
}
Database db = new Database();
try // Check to see if database exists.
{
db = srv.Databases[DB];
if (db == null)
{
Console.WriteLine("Database does not exist on the current server,"
+ " Please restart the application");
Console.ReadLine();
System.Environment.Exit(System.Environment.ExitCode);
}
}
catch
{
Console.WriteLine("Database does not exist on the current server,"
+ " Please restart the application");
Console.ReadLine();
System.Environment.Exit(System.Environment.ExitCode);
}
string allSP = "";
for (int i = 0; i < db.StoredProcedures.Count; i++)
{
//Define a StoredProcedure object variable by supplying the parent database
//and name arguments in the constructor.
StoredProcedure sp;
sp = new StoredProcedure();
sp = db.StoredProcedures[i];
if (!sp.IsSystemObject)// Exclude System stored procedures
{
if (!sp.IsEncrypted) // Exclude already encrypted stored procedures
{
string text = "";// = sp.TextBody;
sp.TextMode = false;
sp.IsEncrypted = true;
sp.TextMode = true;
sp.Alter();
Console.WriteLine(sp.Name); // display name of the encrypted SP.
sp = null;
text = null;
}
}
}
I have the same problem.
My solution is to put "-- WITH ENCRYPTION" in all of my stored procedures. This version is used by developers and stored in source control.
I then use a tool (like sed) in my build to replace "-- WITH ENCRYPTION" with "WITH ENCRYPTION" on the files before I send them to be installed.
For a pure SQL solution you could use REPLACE.
WITH ENCRYPTION means that the code behind the proc is not stored in the SysComments table.
You could write a script that does a exec sp_helptext 'MyProcName' and gets the contents into a VarChar (MAX) so it can hold multiline / large procedures easily and then modifiy the procedure from it's original state
CREATE MyProcName AS
SELECT SecretColumns From TopSecretTable
change CREATE to ALTER and AS surrounded by space or tab or newline (good place to use Regular Expressions) to WITH ENCRYPTION AS
ALTER MyProcName WITH ENCRYPTION AS
SELECT SecretColumns From TopSecretTable
This will hide all code for the stored proc on the production server.
You can put this in a LOOP or a CURSOR (not really a set based operation IMHO) for all objects of a specific type and/or naming convention that you want to encrypt, and run it every time you deploy.
I would recommend creating the sproc in a multi-line string variable and then inserting or altering it using sp_executesql. The only annoying downside to this approach is doubling of single quotes for strings.
DECLARE #action varchar(max);
SET #action = 'CREATE'; /* or "ALTER" */
DECLARE #withEncryption varchar(max);
SET #withEncryption = ''; /* or "WITH ENCRYPTION" */
DECLARE #sql varchar(max);
SET #sql = #action + ' PROCEDURE dbo.Something'
(
....
) ' + #withEncryption +
' AS
BEGIN
DECLARE #bob varchar(10);
SET #bob = ''Bob'';
....
END;
';
EXEC sp_executesql #statement = #sql;
[Note the whitespace around the variables.]
All of my scripts use this method, which works well once you get used to the quote doubling thing.
I also use a batch file to call the script, and SQLCMD-mode command line variables to select various behaviours, which makes it repeatable and easy to test.
Use This Query which Encrypt All Procedures in database
CREATE TABLE #backup
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX) NOT NULL,
spname NVARCHAR(100) NOT NULL,
encrypttext NVARCHAR(MAX) NULL,
encryptstatus BIT NOT NULL
DEFAULT ( 0 )
)
DECLARE #sptexttable TABLE
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX),
spname NVARCHAR(100)
)
INSERT INTO #sptexttable ( sptext, spname )
SELECT [text],
[name]
FROM syscomments
JOIN sysobjects ON syscomments.id = sysobjects.id
AND sysobjects.xtype = 'p'
DECLARE #sptext NVARCHAR(MAX)
DECLARE #spname NVARCHAR(100)
DECLARE #counter INT
SET #counter = 1
WHILE #counter <= ( SELECT MAX(id)
FROM #sptexttable
)
BEGIN
BEGIN TRY
INSERT INTO #backup ( sptext, spname )
SELECT sptext,
spname
FROM #sptexttable
WHERE id = #counter
END TRY
BEGIN CATCH
END CATCH
IF NOT EXISTS ( SELECT [name]
FROM sysobjects
WHERE [name] = 'ce_LastIndexOf'
AND xtype = 'FN' )
BEGIN
EXEC
( 'CREATE FUNCTION ce_LastIndexOf
(
#strValue VARCHAR(4000),
#strChar VARCHAR(50)
)
RETURNS INT
AS BEGIN
DECLARE #index INT
SET #index = 0
WHILE CHARINDEX(#strChar, #strValue) > 0
BEGIN
SET #index = #index
+ CASE WHEN CHARINDEX(#strChar, #strValue) > 1
THEN ( LEN(#strValue) - LEN(SUBSTRING(#strValue,
CHARINDEX(#strChar, #strValue)
+ LEN(#strChar),
LEN(#strValue))) )
ELSE 1
END
SET #strValue = SUBSTRING(#strValue,
CHARINDEX(#strChar, #strValue)
+ LEN(#strChar), LEN(#strValue))
END
RETURN #index
END'
)
END
DECLARE #tempproc NVARCHAR(MAX)
DECLARE #procindex INT
DECLARE #beginindex INT
DECLARE #header NVARCHAR(MAX)
DECLARE #asindex INT
DECLARE #replacetext NVARCHAR(MAX)
SET #tempproc = ( SELECT sptext
FROM #sptexttable
WHERE id = #counter
)
IF ( SELECT CHARINDEX('CREATE PROC', UPPER(#tempproc))
) > 0
BEGIN
BEGIN TRY
SELECT #procindex = CHARINDEX('PROC', UPPER(#tempproc))
PRINT #procindex
SELECT #beginindex = CHARINDEX('BEGIN', UPPER(#tempproc))
PRINT #beginindex
SELECT #header = SUBSTRING(#tempproc, #procindex,
#beginindex - #procindex)
SELECT #asindex = ( SELECT dbo.ce_lastindexof(#header, 'AS')
- 2
)
SELECT #replacetext = STUFF(#header, #asindex, 10,
CHAR(13) + 'WITH ENCRYPTION'
+ CHAR(13) + 'AS' + CHAR(13))
SET #tempproc = REPLACE(#tempproc, #header, #replacetext)
END TRY
BEGIN CATCH
END CATCH
END
UPDATE #sptexttable
SET sptext = #tempproc
WHERE id = #counter
--PLAY HERE TO M AKE SURE ALL PROCS ARE ALTERED
UPDATE #sptexttable
SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',
'ALTER PROC')
FROM #sptexttable
WHERE id = #counter
)
WHERE id = #counter
SELECT #sptext = sptext,
#spname = spname
FROM #sptexttable
WHERE id = #counter
BEGIN TRY
EXEC ( #sptext
)
UPDATE #backup
SET encrypttext = #sptext,
encryptstatus = 1
WHERE id = #counter
END TRY
BEGIN CATCH
PRINT 'the stored procedure ' + #spname
+ ' cannot be encrypted automatically'
END CATCH
SET #counter = #counter + 1
END
SELECT *
FROM #backup
I wrote a cursor, steps through and encrypts most objects.
DECLARE cur_ENCRYPT_ANTHING CURSOR READ_ONLY
FOR
SELECT STUFF(src.definition,
CASE WHEN CHARINDEX('AS' + CHAR(13),src.definition,1) = 0
THEN CASE WHEN CHARINDEX('AS ' + CHAR(13),src.definition,1) = 0 THEN CHARINDEX('AS ',src.definition,1)
ELSE CHARINDEX('AS ' + CHAR(13),src.definition,1)
END
ELSE CHARINDEX('AS' + CHAR(13),src.definition,1)
END,3,'WITH ENCRYPTION AS' + CHAR(13))
FROM (SELECT o.name
, STUFF(RIGHT(sm.definition,LEN(sm.definition) - CHARINDEX('CREATE ',sm.definition,1) + 1),1,6,'ALTER') AS definition
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
WHERE CAST(CASE WHEN sm.definition IS NULL THEN 1
ELSE 0
END AS BIT) = 0
AND type <> 'TR'
) AS src
DECLARE #VLS NVARCHAR(MAX)
OPEN cur_ENCRYPT_ANTHING
FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO #VLS
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
BEGIN TRY
EXEC (#VLS)
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
PRINT ''
PRINT #VLS
END CATCH
END
FETCH NEXT FROM cur_ENCRYPT_ANTHING INTO #VLS
END
CLOSE cur_ENCRYPT_ANTHING
DEALLOCATE cur_ENCRYPT_ANTHING
I have made an update to one of the above answers by removing the dependency on the initial Begin Tag. I had a situation where not all my stored procedures had BEGIN and END.
I used the AS clause instead and also used a case sensitive version of the charindex (by adding a collation)
Its not a perfect solution but helped in getting more of my stored procedures encrypted.
Here is my updated code:
IF OBJECT_ID('tempdb..#backup', 'U') IS NOT NULL
BEGIN
DROP TABLE #backup
END
CREATE TABLE #backup
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX) NOT NULL,
spname NVARCHAR(100) NOT NULL,
encrypttext NVARCHAR(MAX) NULL,
encryptstatus BIT NOT NULL
DEFAULT ( 0 )
)
DECLARE #sptexttable TABLE
(
id BIGINT IDENTITY(1, 1),
sptext NVARCHAR(MAX),
spname NVARCHAR(100)
)
INSERT INTO #sptexttable ( sptext, spname )
SELECT [text],
[name]
FROM syscomments
JOIN sysobjects ON syscomments.id = sysobjects.id
AND sysobjects.xtype = 'p'
DECLARE #sptext NVARCHAR(MAX)
DECLARE #spname NVARCHAR(100)
DECLARE #counter INT
SET #counter = 1
WHILE #counter <= ( SELECT MAX(id)
FROM #sptexttable
)
BEGIN
BEGIN TRY
INSERT INTO #backup ( sptext, spname )
SELECT sptext,
spname
FROM #sptexttable
WHERE id = #counter
END TRY
BEGIN CATCH
END CATCH
IF NOT EXISTS ( SELECT [name]
FROM sysobjects
WHERE [name] = 'CaseSensitiveIndex'
AND xtype = 'FN' )
BEGIN
EXEC (
'CREATE FUNCTION dbo.CaseSensitiveIndex(#source nvarchar(max), #pattern VARCHAR(50))
RETURNS int
BEGIN
return CHARINDEX(#pattern COLLATE Latin1_General_CS_AS, #source COLLATE Latin1_General_CS_AS)
END; '
)
end
IF NOT EXISTS ( SELECT [name]
FROM sysobjects
WHERE [name] = 'ce_LastIndexOf'
AND xtype = 'FN' )
BEGIN
EXEC
( 'CREATE FUNCTION ce_LastIndexOf
(#strValue VARCHAR(max),
#strChar VARCHAR(50))
RETURNS INT
AS
BEGIN
DECLARE #index INT
SET #index = 0
WHILE CHARINDEX(#strChar, #strValue) > 0
BEGIN
SET #index = #index + CASE WHEN CHARINDEX(#strChar, #strValue) > 1
THEN
(LEN(#strValue) - LEN(SUBSTRING(#strValue,CHARINDEX(#strChar, #strValue) + LEN(#strChar),LEN(#strValue))))
ELSE
1
END
SET #strValue = SUBSTRING(#strValue,CHARINDEX(#strChar, #strValue) + len(#strChar),LEN(#strValue))
END
RETURN #index
END'
)
END
DECLARE #tempproc NVARCHAR(MAX)
DECLARE #procindex INT
DECLARE #beginindex INT
DECLARE #header NVARCHAR(MAX)
DECLARE #asindex INT
DECLARE #replacetext NVARCHAR(MAX)
SET #tempproc = ( SELECT sptext
FROM #sptexttable
WHERE id = #counter
)
IF ( SELECT CHARINDEX('CREATE PROC', UPPER(#tempproc))
) > 0
BEGIN
BEGIN TRY
SELECT #procindex = CHARINDEX('PROC', UPPER(#tempproc))
PRINT #procindex
SELECT #beginindex=(select dbo.CaseSensitiveIndex(#tempproc, 'AS'))
if(#beginindex=0) begin set #beginindex=( SELECT dbo.ce_lastindexof(#tempproc, 'AS'))end
SELECT #header = SUBSTRING(#tempproc, #procindex,
#beginindex )
SELECT #asindex = ( SELECT dbo.ce_lastindexof(#header, 'AS')
- 2
)
SELECT #replacetext = STUFF(#header, #asindex, 3,
CHAR(13) + 'WITH ENCRYPTION'
+ CHAR(13) + 'AS' + CHAR(13))
SET #tempproc = REPLACE(#tempproc, #header, #replacetext)
END TRY
BEGIN CATCH
END CATCH
END
UPDATE #sptexttable
SET sptext = #tempproc
WHERE id = #counter
--PLAY HERE TO MAKE SURE ALL PROCS ARE ALTERED
UPDATE #sptexttable
SET sptext = ( SELECT REPLACE(sptext, 'CREATE PROC',
'ALTER PROC')
FROM #sptexttable
WHERE id = #counter
)
WHERE id = #counter
SELECT #sptext = sptext,
#spname = spname
FROM #sptexttable
WHERE id = #counter
BEGIN TRY
EXEC ( #sptext)
UPDATE #backup
SET encrypttext = #sptext,
encryptstatus = 1
WHERE id = #counter
END TRY
BEGIN CATCH
PRINT 'the stored procedure ' + #spname
+ ' cannot be encrypted automatically'
END CATCH
SET #counter = #counter + 1
END
SELECT *
FROM #backup where encryptstatus =0
1) I export Create code for SP and functions. Keep it backed up. for example D:\SP2.sql"
2) this transact SQL code, generate the script to delete existing sP & Functions
SELECT 'DROP PROCEDURE [' + SCHEMA_NAME(p.schema_id) + '].[' + p.NAME + ']' as A
FROM sys.procedures p
union
SELECT 'DROP FUNCTION ' + [name]
FROM sysobjects WHERE [type] IN (N'FN', N'IF', N'TF', N'FS', N'FT') AND category = 0
order by a
3) This Poweshell code
replace
AS
BEGIN
by
WITH ENCRYPTION
AS
BEGIN
The code
$File = "D:\SP2.sql"
$File2 = $File.Replace("SP2.sql","SP-WithEncrypt.sql")
$sortie=""
$SP = get-content -path $file
echo $SP.Count
For ($i = 0 ; $i -le $SP.Count)
{ if ($sp[$i] -eq "AS" -and $sp[$i+1] -eq "BEGIN")
{ $AEcrire = "`nWITH ENCRYPTION `n AS `n BEGIN"
$i+=1
}
else
{$AEcrire =$sp[$i]
}
$sortie += "`n$AEcrire"
$i+=1
$SP.Count-$i
}
$sortie| out-file $File2
Would be faster with a .replace( ,), but problem with End of lines...
4) run the SP-WithEncrypt.sql in SSMS
How to get all the database names and corresponding table names together ?
CREATE TABLE #dbs ( DatabaseName VARCHAR(256), TableName VARCHAR(256) )
EXEC sp_msforeachdb 'INSERT INTO #dbs
SELECT ''?'', [name] FROM dbo.SysObjects WHERE XType = ''U'''
SELECT * FROM #dbs
DROP TABLE #dbs
You will have to write a store procedure.
First get the database name
SELECT Name FROM master.sys.databases
For each database
SELECT %DatabaseName%, Name FROM %DatabaseName%.SysObjects WHERE type = 'U'
Edit here's the store procedure
CREATE PROCEDURE sp_GetDatabasesTables
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
CREATE TABLE #schema ( DatabaseName VarChar(50), TableName VarChar(50) );
DECLARE #DatabaseName varchar(50);
DECLARE cursorDatabase CURSOR FOR
SELECT Name FROM master.sys.databases WHERE Name NOT IN ('tempdb'); -- add any table you want to filter here
OPEN cursorDatabase;
-- Perform the first fetch.
FETCH NEXT FROM cursorDatabase INTO #DatabaseName;
-- Check ##FETCH_STATUS to see if there are any more rows to fetch.
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC ('INSERT INTO #schema (DatabaseName, TableName) SELECT ''' + #DatabaseName + ''' AS DatabaseName, Name As TableName FROM ' + #DatabaseName + '.sys.SysObjects WHERE type = ''U'';');
FETCH NEXT FROM cursorDatabase INTO #DatabaseName;
END
CLOSE cursorDatabase;
DEALLOCATE cursorDatabase;
SELECT * FROM #schema
END