SQL Server: Can you help me with this query? - sql-server-2008

I want to run a diagnostic report on our SQL Server 2008 database server.
I am looping through all of the databases, and then for each database, I want to look at each table. But, when I go to look at each table (with tbl_cursor), it always picks up the tables in the database 'master'.
I think it's because of my tbl_cursor selection :
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
How do I fix this?
Here's the entire code:
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #db_cursor VARCHAR(100)
DECLARE database_cursor CURSOR FOR
SELECT name FROM sys.databases where name<>N'master'
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #db_cursor
WHILE ##Fetch_status = 0
BEGIN
PRINT #db_cursor
SET #table_count = 0
DECLARE #table_cursor VARCHAR(100)
DECLARE tbl_cursor CURSOR FOR
SELECT table_name FROM information_schema.tables WHERE table_type = 'base table'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor INTO #table_cursor
WHILE ##Fetch_status = 0
BEGIN
DECLARE #table_cmd NVARCHAR(255)
SET #table_cmd = N'IF NOT EXISTS( SELECT TOP(1) * FROM ' + #table_cursor + ') PRINT N'' Table ''''' + #table_cursor + ''''' is empty'' '
--PRINT #table_cmd --debug
EXEC sp_executesql #table_cmd
SET #table_count = #table_count + 1
FETCH NEXT FROM tbl_cursor INTO #table_cursor
END
CLOSE tbl_cursor
DEALLOCATE tbl_cursor
PRINT #db_cursor + N' Total Tables : ' + CAST( #table_count as varchar(2) )
PRINT N'' -- print another blank line
SET #table_count = 0
FETCH NEXT FROM database_cursor INTO #db_cursor
END
CLOSE database_cursor
DEALLOCATE database_cursor
SET NOCOUNT OFF

The problem is because you're actually always running the INFORMATION_SCHEMA.TABLES query under the master db context.
You'd need to convert the tbl_cursor block into dynamic SQL in order to fully qualify the query with the DB name.
e.g.
SELECT table_name FROM YourDatabase.INFORMATION_SCHEMA.TABLES WHERE....
is essentially what you need to be executing for that cursor.

It's easier to use table variables so you can add rows to #tablist using another dynamic SQL statement
SET NOCOUNT ON
DECLARE #table_count INT
DECLARE #dblist TABLE (DBName VARCHAR(100))
DECLARE #tablist TABLE (TableName VARCHAR(100))
DECLARE #dbname varchar(100), #tabname varchar(100)
INSERT #dblist
SELECT name FROM sys.databases where name<>N'master'
SELECT TOP 1 #dbname = DBName FROM #dblist
WHILE ##ROWCOUNT <> 0
BEGIN
INSERT #tablist (tableName)
EXEC ('SELECT table_name FROM ' + #dbname + '.information_schema.tables WHERE table_type = ''base table'' ')
SELECT TOP 1 #tabname = tableName FROM #tablist
WHILE ##ROWCOUNT <> 0
BEGIN
--do my stuff
DELETE #tablist WHERE tableName = #tabname
SELECT TOP 1 #tabname = tableName FROM #tablist
END
DELETE #dblist WHERE DBName = #dbname
SELECT TOP 1 #dbname = DBName FROM #dblist
END

You might have to create dynamic SQL. because information_schema will fetch objects only from the current active database against which you are running this query.
you can try sys.objects

Related

Execute a query for all tables and fill in data in new one

I need to get the result table with there fields
- table_name, min_date, max_date
Here is my query, which I should execute for all tables
SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM testTable
GROUP BY short_date
HAVING COUNT(*) > 1) as Duplicates
Then I found out how to get all table names
I do it in this way
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
But I don't know how to execute it for all table and fill in the result in a new table.
I tried to do it in this way
DECLARE #DB_Name varchar(50)
DECLARE #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
But I got this error
Syntax error or access violation: 1064 You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'DECLARE #DB_Name varchar(50) DECLARE
#Command varchar(100)' at line 1
UPD
CREATE PROCEDURE GetData()
BEGIN
DECLARE #DB_Name varchar(50), #Command varchar(100);
DECLARE database_cursor CURSOR FOR
SELECT name
FROM (SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%_') as TableNames
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM ' + #DB_Name + '
WHERE type = ''test''
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates'
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END;
CLOSE database_cursor
DEALLOCATE database_cursor
END;
CALL GetData()
Add DELIMITER $$ at the start; add DELIMITER ; after END.
Get rid of declaring Command. Instead use #command, which does not need to be declared.
Add SELECT #command; after the SELECT #command := ...; so that we can do some debugging.
The CLOSE and DEALLOCATE statements need ; to terminate them.
Test for running out of rows to FETCH.
You really need to look at a number of examples of Stored procedures, especially those with cursors.
Update
Ugh, I did not spot even half the syntax errors. This might work (I can't tell because I don't have your particular tables or columns.):
DROP PROCEDURE IF EXISTS so42856538;
DELIMITER $$
CREATE PROCEDURE so42856538()
LANGUAGE SQL
MODIFIES SQL DATA
SQL SECURITY INVOKER
BEGIN
DECLARE _TableName varchar(64);
DECLARE _done INT DEFAULT FALSE;
DECLARE database_cursor CURSOR FOR
SELECT TABLE_NAME
FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA` = 'test'
AND `TABLE_NAME` LIKE 'test%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET _done = TRUE;
OPEN database_cursor;
curs_loop: LOOP
FETCH NEXT FROM database_cursor INTO _TableName;
IF _done THEN LEAVE curs_loop; END IF;
SET #Command := CONCAT(
'SELECT MIN(short_date) as FirstDuplicatedDate,
MAX(short_date) as LastDuplicatedDate
FROM ( SELECT short_date, type, value, count(*) as cnt
FROM ', _TableName, '
WHERE type = "test"
GROUP BY short_date, type, value
HAVING COUNT(*) > 1 ) as Duplicates'
);
SELECT _TableName, #command; -- Debugging (remove if it is clutter)
PREPARE _sql FROM #command;
EXECUTE _sql;
DEALLOCATE PREPARE _sql;
END LOOP;
CLOSE database_cursor;
END $$
DELIMITER ;
CALL so42856538;
right... you might want to try this.
remove this line and run the query again.
DECLARE #DB_Name varchar(50), #Command varchar(100);
i think in mysql you can just use a variable without declaring it and then cast when necessary.
As far as my knowledge concern this error is due to ,DELIMETER and one more thing that you have to apply cursor properly to iterate whole rowset.Here in below code i had wrote down procedure with CURSOR.Make dynamic query and execute that dynamic query using
PREPARE stmt FROM #VAR_QRY; EXECUTE stmt;
That dynamic query will returns exact output you want.Here i had assuming that you have basic knowledge about trigger,loop and Cursor
Try below code.
Hope this will helps.
DROP PROCEDURE IF EXISTS ITERATEALLTABLE;
DELIMITER $$
CREATE PROCEDURE ITERATEALLTABLE()
BEGIN
DECLARE VAR_TABLE varchar(100);
DECLARE VAR_QRY varchar(100);
DECLARE VAR_FINISHED INT(11) DEFAULT 0;
DECLARE DATABASE_CURSOR CURSOR FOR
SELECT name AS TableNames
FROM (
SELECT TABLE_NAME as name FROM `information_schema`.`TABLES`
WHERE `TABLES`.`TABLE_SCHEMA` = 'test'
AND `TABLES`.`TABLE_NAME` LIKE 'test%'
)Z ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET VAR_FINISHED = 1;
OPEN DATABASE_CURSOR;
GET_NEXTRECORD: LOOP
FETCH DATABASE_CURSOR INTO VAR_TABLE;
IF VAR_FINISHED = 1 THEN
LEAVE GET_NEXTRECORD;
END IF;
SET #VAR_QRY = CONCAT("SELECT MIN(short_date) as FirstDuplicatedDate, MAX(short_date) as LastDuplicatedDate
FROM (SELECT short_date, type, value, count(*) as cnt
FROM " , VAR_TABLE , " WHERE type = 'test'
GROUP BY short_date, type, value
HAVING COUNT(*) > 1) as Duplicates");
PREPARE stmt FROM #VAR_QRY;
EXECUTE stmt;
END LOOP GET_NEXTRECORD;
CLOSE DATABASE_CURSOR;
END;
CALL ITERATEALLTABLE;

Alter table with same name in multiple schema

I have table with same name (name-xxx) in 100 different schema in same mysql server.
I want to alter all table named xxx by using a single script (without hard coding
the schema name in the script)
You can try something like that:
DECLARE #alterQ NVARCHAR(max)
DECLARE #table_name VARCHAR(45)
DECLARE tables_curs CURSOR FOR
SELECT t.table_name
FROM INFORMATION_SCHEMA.TABLES t
WHERE t.table_name = 'xxx'
AND t.table_catalog = 'db_name'
OPEN tables_curs
FETCH tables_curs INTO #table_name
WHILE ##Fetch_Status = 0
BEGIN
SET #table_name = N'ALTER TABLE #table_name ...'
EXEC sp_executesql #alterQ
END
CLOSE tables_curs
DEALLOCATE tables_curs

Dropping indexes in SQL Server database

How do you drop indexes in a SQL Server 2008 database? This is what I've got so far:
declare #procname varchar(500)
declare cur cursor
for
select name from sysindexes
open cur
fetch next from cur into #procname
while ##FETCH_STATUS=0
begin
exec ('drop index ' + #procname)
fetch next from cur into #procname
end
close cur
deallocate cur
You need to use something like this, because the DROP INDEX statement requires you to specify the table name:
-- define variables for index, schema and table name
DECLARE #indexname sysname
DECLARE #schemaname sysname
DECLARE #tablename sysname
-- declare variable for actual DROP statement
DECLARE #dropstatement NVARCHAR(1000)
-- declare cursor for iterating over all indexes
DECLARE index_cursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT ix.name, t.name, s.name
FROM sys.indexes ix
INNER JOIN sys.tables t ON t.object_id = ix.object_id
INNER JOIN sys.schema s ON t.schema_id = s.schema_id
WHERE t.is_ms_shipped = 0
-- open cursor
OPEN index_cursor
-- get first index, table and schema name
FETCH NEXT FROM index_cursor INTO #indexname, #tablename, #schemaname
WHILE ##FETCH_STATUS = 0
BEGIN
-- define the DROP statement
SET #dropstatement = N'DROP INDEX ' + QUOTENAME(#indexname) +
N' ON ' QUOTENAME(#schemaname) + N'.' +
QUOTENAME(#tablename)
-- execute the DROP statement
EXEC sp_executesql #dropstatement
-- get next index, table and schema name
FETCH NEXT FROM index_cursor INTO #indexname, #tablename, #schemaname
END
CLOSE index_cursor
DEALLOCATE index_cursor

MySQL - Removing null value rows from table

I have a table "user" with over 60 columns. One of the column's name is "username"
I want to remove the rows where the username field is empty or NULL
How can I do this?
Thank you!
Try this
DELETE FROM user WHERE username IS NULL;
or
DELETE FROM user WHERE username = '';
Problems with NULL Values
If you want to delete all those rows containing username = NULL AND where username is empty string ("") as well
then
DELETE FROM table_name WHERE username IS NULL OR username = '';
It is advised to first do a SELECT query with same WHERE condition as that you are going to use in DELETE query to see which rows will be deleted:
SELECT * FROM table_name WHERE username IS NULL OR username = "";
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
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

SQL - Get databases which contain a specific record

So originally I have this as a test run.
SELECT DISTINCT table_schema FROM information_schema.columns WHERE table_schema LIKE '%or';
I have looked around and found queries to show all the databases that contain a specific table.
However is it possible to have a query to go a step further and do the following:
"Select all those databases that have a particular table in them and that, in that table, have a particular record in a particular column."?
You cannot do what you want with a SQL statement.
But, you can use SQL to generate the statement that you want. The basic statement is:
select "tablename"
from tablename
where columnname = value
limit 1
Note that value may need to have single quotes around it. You can generate this with:
select concat('select "', c.table_name, '" ',
'from ', c.schema_name, '.', c.table_name, ' ',
'where ', c.column_name, ' = ', VALUE, ' '
'limit 1'
)
from information_schema.columns c
where c.table_name = TABLENAME and c.column_name = COLUMN_NAME;
To put all the statements in one long SQL statement, use:
select group_concat(concat('select "', c.table_name, '" as table_name',
'from ', c.schema_name, '.', c.table_name, ' ',
'where ', c.column_name, ' = ', VALUE, ' '
'limit 1'
) SEPARATOR ' union all '
)
from information_schema.columns c
where c.table_name = TABLENAME and c.column_name = COLUMN_NAME;
I would then just copy the resulting SQL statement and run it. If you like, you can add a prepare statement and run it dynamically.
as an example,
I have a table named T1 with columns (C1,C2), and I am searching for the value 'Needle'.
What this store procedure does is search through table names that starts with T and columns that starts with C, then loop through them and finds the value 'Needle'. It then returns the table_Schema,table_name,column_name and how many times the value 'Needle' is found within that column_name,table_name,table_schema combination.
see this sqlFiddle
CREATE PROCEDURE findDatabase(IN in_value varchar(50))
BEGIN
DECLARE bDone INT;
DECLARE _TableSchema VARCHAR(50);
DECLARE _TableName VARCHAR(50);
DECLARE _ColumnName VARCHAR(50);
DECLARE curs CURSOR FOR SELECT TABLE_SCHEMA,TABLE_NAME,COLUMN_NAME FROM information_schema.columns WHERE TABLE_NAME LIKE "T%" AND COLUMN_NAME LIKE "C%";
DECLARE CONTINUE HANDLER FOR NOT FOUND SET bDone = 1;
DROP TEMPORARY TABLE IF EXISTS tblResults;
CREATE TEMPORARY TABLE IF NOT EXISTS tblResults (
id int auto_increment primary key,
tableSchema varchar(50),
tablename varchar(50),
columnname varchar(50),
timesFound int
);
OPEN curs;
SET bDone = 0;
REPEAT
FETCH curs INTO _TableSchema,_TableName,_ColumnName;
SET #found = 0;
SET #sql = CONCAT("SET #found = (SELECT COUNT(*) FROM ",_TableSchema,".",_TableName,
" WHERE ",_ColumnName,"='",in_value,"')");
PREPARE statement FROM #sql;
EXECUTE statement;
IF (#found > 0) THEN
INSERT INTO tblResults(tableSchema,tableName,columnName,TimesFound) VALUES (_TableSchema,_TableName,_ColumnName,#found);
END IF;
UNTIL bDone END REPEAT;
CLOSE curs;
SELECT DISTINCT TableSchema,TableName,ColumnName,TimesFound FROM tblResults;
DROP TABLE tblResults;
END//