Force the output query to shows the DB_NAME() data once - sql

I've got a query that selects all indexes from a table and generate an output text to drop them individually.
I want to put the DB_NAME() info in the beginning of command for once, but at this moment the data is showed at every index drop.
I've tried to put a select before, but without success.
Could someone help me? Query and results are below:
- QUERY
SELECT
'USE ' + QUOTENAME(db_name()) + ';' + CHAR(13) +
'GO ' + CHAR(13) +
'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.Name) + ';' + CHAR(13) +
'GO'
FROM
sys.indexes i
JOIN sys.tables t ON t.object_id = i.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE
t.Name = 'Queue';
- Results that I get (example)
USE [master];
GO
DROP INDEX [PK_Queue] ON [dbo].[Queue];
GO
USE [master];
GO
DROP INDEX [I_001] ON [dbo].[Queue];
GO
USE [master];
GO
DROP INDEX [I_002] ON [dbo].[Queue];
GO
- Results that I want
USE [master];
GO
DROP INDEX [PK_Queue] ON [dbo].[Queue];
GO
DROP INDEX [I_001] ON [dbo].[Queue];
GO
DROP INDEX [I_002] ON [dbo].[Queue];
GO

You can just initialize a variable with the USE command, and then append the DROP INDEX commands using string concatenation. This is easier in SQL Server 2017 (STRING_AGG()), but you didn't tell us what version you use, so...
DECLARE #sql nvarchar(max) = N'USE ' + QUOTENAME(db_name()) + ';';
SELECT #sql += char(13) + N'GO' + char(13) + N'DROP INDEX '
+ QUOTENAME(i.name) + ' ON ' + QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ';' + CHAR(13)
FROM
sys.indexes i
JOIN sys.tables t ON t.object_id = i.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE
t.Name = 'Queue' AND i.name IS NOT NULL;
PRINT #sql;
Example db<>fiddle

SELECT Txt
from
(
SELECT
1 as Seq,
'USE ' + QUOTENAME(db_name()) + ';' + CHAR(13) +
'GO ' + CHAR(13) as Txt
union all
SELECT
2 as Seq,
'DROP INDEX ' + QUOTENAME(i.name) + ' ON ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.Name) + ';' + CHAR(13) +
'GO'
FROM
sys.indexes i
JOIN sys.tables t ON t.object_id = i.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE
t.Name = 'Queue'
) S1
order by Seq
But, why bother? You can script almost everything in SQL Server Management Studio as #shreepat18 said!

Related

Search for a value in all column and all tables of a database

I want to find the column name that contain the value "Commerciale", but i do not know the column name or the table so I need to search in the whole database. How can i do that with a query?
I'm using SQL SERVER
If you are looking for columns where the name is Commerciale then you can simply use the sys objects:
SELECT s.[name] AS SchemaName,
t.[name] AS TableName,
c.[name] AS ColumnName
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 c.[name] = N'Commerciale';
If, however, you need to search the contents of the values in the rows, you'll need to use dynamic SQL. This will return a dataset for every table in your database which has at least 1 string type column, and will return any rows where the value of one of those columns has the value 'Commerciale'. If it needs to contain the value, change the WHERE to use a LIKE in it's clauses instead (note the query will be horrifically slow with that):
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10);
SET #SQL = STUFF((SELECT #CRLF +
N'SELECT N' + QUOTENAME(s.[name],'''') + N' AS SchemaName,' + #CRLF +
N' N' + QUOTENAME(t.[name],'''') + N' AS TableName,' + #CRLF +
N' *' + #CRLF +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + #CRLF +
N'WHERE ' +
STUFF((SELECT #CRLF +
N' AND ' + QUOTENAME(c.[name]) + N' = ''Commerciale'''
FROM sys.columns c
JOIN sys.types ct ON c.system_type_id = ct.system_type_id
WHERE c.object_id = t.object_id
AND ct.[name] IN (N'char',N'varchar',N'nchar',N'nvarchar')
FOR XML PATH(''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,8,N'') + N';'
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
FOR XML PATH(''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,2,N'');
--PRINT #SQL; --YOu best friend
EXEC sp_executesql #SQL;
This won't tell you what column has the value, you'll need to use your own eyes to do that, but I wasn't entertaining writing a dynamic table dynamic pivot.
you can use system tables :
SELECT
c.name ColumnName
, t.name TableName
FROM sys.columns AS c
JOIN sys.tables AS t
ON c.object_id = t.object_id
WHERE c.name like '%Commerciale%'

Put single quotes into single quotes in SQL Server string

I have the update query below.
update tableName
set columnName = null
where isnull(columnName, '') = ''
I want to put single quotes in a SQL Server string builder query so that the above query can be executed for every column in the table. See this query:
Declare #sql2 varchar(max) = ''
declare #tablename2 as varchar(255) = 'test2'
select #sql2 = #sql2 + 'update [' + #tablename2 + '] set [' + c.name +']' + ' = NULL ' +
' WHERE ISNULL([' + c.name + '], ' + '' + ') = ' + ''
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename2
EXEC (#sql2)
go
Below is test data.
create table test2
(
test varchar(50)
)
insert into test2
values (' ewewwe'), ('sdsddsds '), ('')
I get this error while executing the SQL String builder query:
Incorrect syntax near ') = '
What am I doing wrong?
The error you receive is because the statement string is not valid. You end up with an unescaped string.
You need to add an escaped quote ('') for each quote you need, ('''''') like this:
Declare #sql2 varchar(max) =''
declare #tablename2 as varchar(255) ='test2'
select #sql2 = #sql2 + 'update [' + #tablename2 + '] set [' + c.name + ']' + ' = NULL ' +
' WHERE ISNULL([' + c.name + '], ' + '''''' + ') = ' + ''''''
from sys.columns c
inner join sys.tables t on c.object_id = t.object_id
where t.name = #tablename2
EXEC (#sql2)
go
when you use isnull, you have to provide 2 parameters
' WHERE ISNULL([' + c.name + '], ' + '???' + ') = ' + ''
You need to provide something for the ??? and currently its empty
Replace with
WHERE ISNULL([' + c.name + '], ' + '''''' + ')
Single quotes are self-escaped; that is, you put two together in a literal to get one in the final string.
Additionally, you want the QUOTENAME() function to handle enclosing these fields. It's smart enough to also account for names that might include braces or other weirdness, plus you can expect it to be updated if anything else is ever added to the language that might interfere:
DECLARE #sql2 varchar(max) = ''
DECLARE #tablename2 as varchar(255) = 'test2'
SELECT #sql2 = #sql2 +
'update ' + QUOTENAME(#tablename2) +
' set ' + QUOTENAME(c.name) + ' = NULL' +
' WHERE COALESCE(RTRIM(' + QUOTENAME(c.name) + '), '''') = '''' '
FROM sys.columns c
INNER JOIN sys.tables t on c.object_id = t.object_id
WHERE t.name = #tablename2
EXEC(#sql2)

SQL query optimization

I am trying to find out a script that can help me in Data Density of my DBs. the point is I already figure out the query and what I do need but the problem is the query takes for ever. it works find for small DBs, but that doesn't happen a lot.
So I am looking for kind of optimization or any ideas to help me.
the script:
DECLARE Cur CURSOR
FOR
SELECT DB_Name() AS DatabaseName
,s.[name] AS SchemaName
,t.[name] AS TableName
,c.[name] AS ColumnName
,'[' + DB_Name() + ']' + '.[' + s.NAME + '].' + '[' + T.NAME + ']' AS FullQualifiedTableName
,d.[name] AS DataType
FROM sys.schemas s
INNER JOIN sys.tables t ON s.schema_id = t.schema_id
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types d ON c.user_type_id = d.user_type_id
WHERE d.NAME LIKE '%int%'
OR d.NAME LIKE '%float%'
OR d.NAME LIKE '%decimal%'
OR d.NAME LIKE '%numeric%'
OR d.NAME LIKE '%real%'
OR d.NAME LIKE '%money%'
OR d.NAME LIKE '%date%'
OR d.NAME LIKE '%datetime%'
AND is_identity = 0
OPEN Cur
FETCH NEXT
FROM Cur
INTO #DatabaseName
,#SchemaName
,#TableName
,#ColumnName
,#FullyQualifiedTableName
,#DataType
WHILE ##FETCH_STATUS = 0 -- The FETCH statement was successful.
BEGIN
DECLARE #SQL VARCHAR(MAX) = NULL
SET #SQL = ' Select ''' + #DatabaseName + ''' AS DatabaseName, ''' +
#SchemaName + ''' AS TableName,
''' + #TableName + ''' AS SchemaName,
''' + #ColumnName + ''' AS ColumnName,
''' + #DataType + ''' AS ColumnName,
(Select MAX(' + #ColumnName + ') from ' + #FullyQualifiedTableName + ' with (nolock))
AS MaxValue,
(Select MIN(' + #ColumnName + ') from ' + #FullyQualifiedTableName + ' with (nolock))
AS MinValue,
(Select COUNT(*) from ' + #FullyQualifiedTableName + ' with (nolock))
AS CountValue,
(Select COUNT(*) from ' + #FullyQualifiedTableName + ' Where ' + #ColumnName + ' IS NOT NULL )
AS NotNULLCount,
(Select 0 from ' + #FullyQualifiedTableName + ')
AS DataDensity'
PRINT #SQL
The following script will give me the MAX, MIN, COUNT, NotNULLCount and the DATA DENSITY for every and each column form the declared types above. but u can imagine a DB with 70 tables and each table has 30-50 columns....
running this script will take for ever.
You should always try and avoid using cursors, this query will give you a list of select queries that you can copy and paste to get the data that you require. Note also I have removed the sub selects as they are not required:
SELECT 'Select ''' + DB_Name() + ''' AS DatabaseName, ''' + s.Name + ''' AS SchemaName, ''' + t.Name + ''' AS TableName, ''' + c.Name + ''' AS ColumnName, ''' + d.Name + ''' AS ColumnName,' +
'MAX([' + c.Name + ']) AS MaxValue,' +
'MIN([' + c.Name + ']) AS MinValue,' +
'COUNT(*) AS CountValue,' +
'COUNT([' + c.Name + ']) AS NotNullCount,' +
'CAST(COUNT(DISTINCT [' + c.name + ']) AS float) / COUNT([' + C.Name + ']) AS DataDensity ' +
'from [' + DB_Name() + '].[' + s.Name + '].[' + t.name + '] with (nolock)'
FROM sys.schemas s
INNER JOIN sys.tables t ON s.schema_id = t.schema_id
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.types d ON c.user_type_id = d.user_type_id
WHERE d.NAME LIKE '%int%'
OR d.NAME LIKE '%float%'
OR d.NAME LIKE '%decimal%'
OR d.NAME LIKE '%numeric%'
OR d.NAME LIKE '%real%'
OR d.NAME LIKE '%money%'
OR d.NAME LIKE '%date%'
OR d.NAME LIKE '%datetime%'
AND is_identity = 0
This will give you a list of select statements in the following form:
Select 'MyDB' AS DatabaseName, 'dbo' AS SchemaName, 'MyTable' AS TableName, 'ID' AS ColumnName, 'int' AS ColumnName,MAX([ID]) AS MaxValue,MIN([ID]) AS MinValue,COUNT(*) AS CountValue,COUNT([ID]) AS NotNullCount,CAST(COUNT(DISTINCT [ID]) AS float) / COUNT([ID]) AS DataDensity from [MyDB].[dbo].[MyTable] with (nolock)
Of course SQL Server stores these sorts of statistics for useful columns, You can find which ones it has be using:
EXEC SP_HELPSTATS 'MyTable', 'ALL'
Then using the list of statistics returned such as:
_WA_Sys_00000014_004FB3FB ID
to get the actual stats using:
DBCC SHOW_STATISTICS('MyTable','_WA_Sys_00000002_004FB3FB')
This will return data like:
Name Updated Rows Rows Sampled Steps Density Average key length String Index Filter Expression Unfiltered Rows
_WA_Sys_00000002_004FB3FB Jan 8 2017 8:01PM 16535 16535 200 0.2493151 4.459389 NO NULL 16535
and
All density Average Length Columns
0.0006038647 4.459389 EffectiveDate
and another rowset showing a histogram of values.
You can automatically generate these DBCC commands using:
SELECT 'DBCC SHOW_STATISTICS([' + OBJECT_NAME(s.object_Id) + '],''' + s.Name + ''')'
FROM sys.stats s
INNER JOIN sys.stats_columns sc
ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
INNER JOIN sys.columns c
ON sc.object_id = c.object_id AND sc.column_id = c.column_id
WHERE s.Name LIKE '_WA%'
ORDER BY s.stats_id, sc.column_id;

SQL SERVER QUERY EXEC sp_helptext

I want to use EXEC sp_helptext for each stored procedure in the database.
So I would like to use EXEC sp_stored_procedures and retrieve the PROCEDURE_NAME from it to execute : EXEC sp_helptext PROCEDURE_NAME in loop.
Any help would be deeply appreciated.
No need to call sp_helptext per proc, you can get them all in a single query:
select sm.definition
from sys.sql_modules sm
inner join sys.objects o on o.object_id = sm.object_id
where o.type = 'P'
select 'PRINT ''SET QUOTED_IDENTIFIER ' + case uses_quoted_identifier when 1 then 'ON''' else 'OFF' + '''' end + char(13) + char(10)
+ 'PRINT ''GO ''' + char(13) + char(10)
+ 'PRINT ''SET ANSI_NULLS ' + case uses_ansi_nulls when 1 then 'ON''' else 'OFF' + '''' end + char(13) + char(10)
+ 'PRINT ''GO ''' + char(13) + char(10)
+ 'GO'
+ char(13) + char(10) + 'sp_helptext ' + o.name + char(13) + char(10) + 'GO' + char(13) + char(10)
+ 'PRINT ''GO ''' + char(13) + char(10)
FROM sys.all_sql_modules AS m
JOIN sys.all_objects AS o
ON m.Object_ID = o.Object_ID
JOIN sys.schemas AS s
ON o.schema_id = s.schema_id
WHERE o.is_ms_shipped=0
------------------------------------------------------
-- custom filters below
------------------------------------------------------
and o.type = 'SP'
So all of that other stuff in the beginning is because sp_helptext doesn't also have whether or not ansi nulls or quoted identifiers were set to anything in particular. This script will create a script that can hopefully be run for your needs.

dropping multiple tables ending with "1617"

I need to drop multiple tables ending with the string "1617"
I have come across massive procedures to do this but is there an easy way
My tables look like mytable1617 and I have loads of them
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += '
DROP TABLE '
+ QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ';'
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name LIKE '1617%';
PRINT #sql;
-- EXEC sp_executesql #sql;
This:
WHERE t.name LIKE '1617%';
is looking for tables starting with 1617. You wanted:
WHERE t.name LIKE '%1617';
Just change the search pattern
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += '
DROP TABLE '
+ QUOTENAME(s.name)
+ '.' + QUOTENAME(t.name) + ';'
FROM sys.tables AS t
INNER JOIN sys.schemas AS s
ON t.[schema_id] = s.[schema_id]
WHERE t.name LIKE '%1617'; --tables ending with 1617
PRINT #sql;