Simple Sql Procedure with/without cursor - sql

Please help me with a simple procedure, lets say on Sql Server (2005, 2008, does not matter).
I have table dbo.[columns] with 1000 lines, which all are the names for some specific table names from a database.
Bottom line is that I need to create a procedure which will parse all 1000 lines of tables,
for each table name found in dbo.[columns] to execute the following
select: select count(*), ''''+[column_name]+'''' from dbo.[column_name]
The result should be like this:
count(*) table_name:
100 employees
0 ex_employees
25 addresses
10 birthdays
Any hints?
Thanks in advance,
Bogdan

SELECT COUNT(Column_With_List_Of_Table_Names_Here)
, Column_With_List_Of_Table_Names_Here
FROM YourDatabase.dbo.YourTable
GROUP BY Column_With_List_Of_Table_Names_Here;

Maybe not what are you asking, but should get the results I think you want. You can use system views to get the row count for each table without running COUNT(*)
SELECT i.rowcnt, o.name FROM sysindexes i
LEFT JOIN sys.objects o ON i.id = o.object_id
WHERE indid <2
ORDER BY name
or
SELECT SUM (row_count) AS ROWS, o.Name AS TableName
FROM sys.dm_db_partition_stats s
LEFT JOIN sys.objects o ON s.object_id = o.object_id AND (index_id=0 or index_id=1)
GROUP BY o.Name
*2nd query should be more precise
Inner joining this queries to your dbo.[columns] can filter the results only for your desired tables.

Try this using CURSOR And Dynamic sql
CREATE TABLE #temp(count_ int,table_name varchar(50))
DECLARE #column_Name VARCHAR(50)
DECLARE #query VARCHAR(500)
DECLARE table_cursor CURSOR FOR
SELECT [column_name] from dbo.[column_name]
OPEN product_cursor
FETCH NEXT FROM product_cursor INTO #column_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query='INSERT INTO #temp SELECT'+ #column_Name+',COUNT(*) FROM'+ #column_Name
EXEC sp_executesql #SQLStatement=#query
/*this will insert the coresponding table name and its row count to #temp*/
END
CLOSE product_cursor
DEALLOCATE product_cursor
select * from #temp

Related

Multiple tables in the where clause that start with the same string

I'm using sql-server 2014 and am trying to select ID values from a table where the ID values do not exist in hundreds of other tables which all start with the same string (e.g. MyTable1, MyTable2, MyTable3, etc.)
My current query is something like this...
select ID from want w
where not exists (select 'x' from MyTable1 m1 where m1.ID = w.id)
and not exists (select 'x' from MyTable2 m2 where m2.ID = w.id)
I'm looking for something like
select ID from want w
where not exists (select 'x' from 'MyTable%' m where m.ID = w.id)
Or
select ID from want w
where ID not in
(select ID from 'MyTable%')
Thank you!
You do mention that there are hundreds of other tables, is the number of tables increasing? Using INFORMATION_SCHEMA.TABLES as already mentioned in the comments in your question along with dynamic SQL would be a start but also look up cursors for looping through the table names with the result-set returned from INFORMATION_SCHEMA.TABLES. The code fragment below will loop through the table listing from information_schema on the default database. You'll have to add your own code depending on what you want to do where the 'if' statement is. The variable #Table_Name has the name of the table, so you would need to include this in a dynamic SQL string and execute this to get your unused ids.
declare #table_name varchar(256);
DECLARE db_cursor CURSOR FOR
SELECT TABLE_NAME
FROM [Datasets].INFORMATION_SCHEMA.TABLES
;
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #TABLE_NAME
WHILE ##FETCH_STATUS = 0
BEGIN
if(#Table_Name like 'Airline%')
print('Have table name to work with: ' + #Table_Name);
else
print('Ignoring table: ' + #Table_name);
FETCH NEXT FROM db_cursor INTO #TABLE_NAME
END
CLOSE db_cursor
DEALLOCATE db_cursor

T-SQL : Can you concatenate query results from a loop into a single table?

So I have this query right here:
OPEN #getid
WHILE ##FETCH_STATUS = 0
Begin
FETCH NEXT
FROM #getid INTO #table, #funckey
set #query = '
select '''+#table+''' as Tab,
(SELECT COUNT(DISTINCT COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME= '''+#table+''') as Columns,
(SELECT COUNT(*) Lines
FROM '+#table+') as Lines
'
EXEC sp_executesql #query
FETCH NEXT
FROM #getid INTO #table, #funckey
END
So I'm trying to get the name, number of columns and number of lines for each database table into a same resulting table, but this method returns one result table by iteration. So I'm wondering how I can concatenate the lines instead of having each one be in its own table.
Is there any way to have all the itérations aliment the same table ?
(i left out some of the variable declaration lines for more clarity)
If my reading of this comment is correct:
I'm trying to get the name, number of columns and number of lines for each database table into a same resulting table, but this method returns one result table by iteration. So I'm wondering how I can concatenate the lines instead of having each one be in its own table.
It seems like you don't need a CURSOR at all, if you're happy with a "good" estimate for the row count.
SELECT s.name AS SchemaName,
t.name AS TableName,
c.Columns,
p.Rows
FROM sys.schemas s
JOIN sys.tables t ON s.schema_id = t.schema_id
CROSS APPLY (SELECT COUNT(*) AS Columns
FROM sys.columns c
WHERE c.object_id = t.object_id) c
CROSS APPLY (SELECT COUNT(*) AS Rows
FROM sys.partitions p
WHERE p.object_id = t.object_id
AND p.index_id IN (0,1)) p;

Is there a way to find all invalid columns that are referenced in a view using SQL Server 2012?

I have inherited a large database project with thousands of views.
Many of the views are invalid. They reference columns that no longer exist. Some of the views are very complex and reference many columns.
Is there an easy way to track down all the incorrect columns references?
This answer finds the underlying columns that were originally defined in the views by looking at sys.views, sys.columns and sys.depends (to get the underlying column if the column has been aliased). It then compares this with the data held in INFORMATION_Schema.VIEW_COLUMN_USAGE which appears to have the current column usage.
SELECT SCHEMA_NAME(v.schema_id) AS SchemaName,
OBJECT_NAME(v.object_id) AS ViewName,
COALESCE(alias.name, C.name) As MissingUnderlyingColumnName
FROM sys.views v
INNER JOIN sys.columns C
ON C.object_id = v.object_id
LEFT JOIN sys.sql_dependencies d
ON d.object_id = v.object_id
LEFT JOIN sys.columns alias
ON d.referenced_major_id = alias.object_id AND c.column_id= alias.column_id
WHERE NOT EXISTS
(
SELECT * FROM Information_Schema.VIEW_COLUMN_USAGE VC
WHERE VIEW_NAME = OBJECT_NAME(v.object_id)
AND VC.COLUMN_NAME = COALESCE(alias.name, C.name)
AND VC.TABLE_SCHEMA = SCHEMA_NAME(v.schema_id)
)
For the following view:
create table test
( column1 varchar(20), column2 varchar(30))
create view vwtest as select column1, column2 as column3 from test
alter table test drop column column1
The query returns:
SchemaName ViewName MissingUnderlyingColumnName
dbo vwtest column1
This was developed with the help of this Answer
UPDATED TO RETRIEVE ERROR DETAILS
So this answer gets you what you want but it isn't the greatest code.
A cursor is used (yes I know :)) to execute a SELECT from each view in a TRY block to find ones that fail. Note I wrap each statement with a SELECT * INTO #temp FROM view X WHERE 1 = 0 this is to stop the EXEC returning any results and the 1=0 is so that SQL Server can optimize the query so that it is in effect a NO-OP.
I then return a list of any views whose sql has failed.
I haven't performed lots of testing on this, but it appears to work. I would like to get rid of the execution of each SELECT from View.
So here it is:
DECLARE curView CURSOR FOR
SELECT v.name AS ViewName
FROM sys.views v
INNER JOIN sys.sql_modules m
on v.object_id = m.object_id
OPEN curView
DECLARE #viewName SYSNAME
DECLARE #failedViews TABLE
(
FailedViewName SYSNAME,
ErrorMessage VARCHAR(MAX)
)
FETCH NEXT FROM curView
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
exec ('SELECT * INTO #temp FROM ' + #viewName + ' WHERE 1=0' )
END TRY
BEGIN CATCH
INSERT INTO #failedViews VALUES (#viewName, ERROR_MESSAGE())
END CATCH
FETCH NEXT FROM curView
INTO #ViewName
END
CLOSE curView
DEALLOCATE curView
SELECT *
FROM #failedViews
An example of an ERROR returned is:
FailedViewName ErrorMessage
--------------- -------------
vwtest Invalid column name 'column1'.
You could use system tables get information.
SELECT v.VIEW_NAME,v.TABLE_CATALOG,v.TABLE_SCHEMA,v.TABLE_NAME,v.COLUMN_NAME
from INFORMATION_SCHEMA.VIEW_COLUMN_USAGE v
left outer join INFORMATION_SCHEMA.COLUMNS c
ON v.TABLE_CATALOG=c.TABLE_CATALOG AND v.TABLE_SCHEMA=c.TABLE_SCHEMA AND v.TABLE_NAME=c.TABLE_NAME AND v.COLUMN_NAME=c.COLUMN_NAME
WHERE c.TABLE_NAME IS NULL
ORDER BY v.VIEW_NAME

get all table names with the primary key row count

I have a scenario, where I need to compare data between two servers.
Long story short, I need a result set which gives the output like
SchemaName|TableName|RowCount_PrimaryKey
Whenever a new student joins a unique schema is created say Stu1200 and this schema has 5 tables like
stu1200.class
stu1200.sub
stu1200.avg
stu1200.work
stu1200.blabla
There are 500 students in our database. So 500 schema. I need to compare all the tables of work of 500 students.
In order to do so I need to get the counts of the primary key, say StuID. So I need to get all the 500 schemas with the table like work.
Something like
SchemaName TableName StuID_Count
stu1200 Work 70
Stu1201 Work 112
Stu1202 Work 9
How can this be done? I have a script which does row counts of the table but its of useless, I need the row counts based only on the primary key.
Note: using SQL Server 2000 :(
Thanks in advance for sharing your suggestions/experience.
Your design is highly questionable but here is a way to get a relatively up-to-date count in an efficient manner. In SQL Server 2005+:
DECLARE #tablename SYSNAME;
SET #tablename = N'Work';
SELECT
SchemaName = OBJECT_SCHEMA_NAME([object_id]),
TableName = #tablename,
RowCount_PrimaryKey = SUM([rows])
FROM sys.partitions
WHERE OBJECT_NAME([object_id]) = #tablename
AND index_id IN (0,1)
GROUP BY OBJECT_SCHEMA_NAME([object_id])
ORDER BY SchemaName;
Just noticed SQL Server 2000.
DECLARE #tablename SYSNAME;
SET #tablename = N'Work';
SELECT
SchemaName = u.name,
TableName = #tablename,
i.rows
FROM
sys.sysindexes AS i
INNER JOIN sys.sysobjects AS o
ON i.id = o.id
INNER JOIN sys.sysusers AS u
ON o.uid = u.uid
WHERE i.indid IN (0,1)
AND o.name = #tablename;

Execute Stored Procedure in a Cursor

I need to execute stored procedure sp_spaceused for all the tables in my database.
I have used cursor for this, please find the below query.The thing is I need to generate report in a single result set.
For the below query I'm getting different results.
Declare #Name Varchar(500)
Declare #GetName Cursor
Set #Getname = Cursor for
select name from sys.tables
Open #Getname
Fetch Next From #Getname into #Name
While ##Fetch_Status=0
Begin
exec sp_spaceused #Name
Fetch Next From #Getname into #Name
End
Close #GetName
Deallocate #GetName
You can use something like the below (the data types may well need tweaking).
Edit: Please see Joe's answer for the correct data types to use!
create table #t
(
name sysname,
rows bigint,
reserved varchar(50),
data varchar(50),
index_size varchar(50),
unused varchar(50)
)
EXEC sp_MSForEachtable 'insert into #t EXEC sp_spaceused ''?'''
select name,rows,reserved,data,index_size,unused
from #t
create table #Temp (
name nvarchar(128),
[rows] char(11),
reserved varchar(18),
data varchar(18),
index_size varchar(18),
unused varchar(18)
)
insert into #Temp
exec sp_msforeachtable 'sp_spaceused [?]'
select * from #Temp
A faster, set-based solution to this problem is to join sys.dm_db_partition_stats and sys.internal_tables, just like sp_spaceused does. The code below is what runs when you generate the "Disk Usage By Table" report in Management Studio.
In my database, the set-based solution returned in 60 ms, while the cursor ran for 22 seconds.
begin try
SELECT
(row_number() over(order by a3.name, a2.name))%2 as l1,
a3.name AS [schemaname],
a2.name AS [tablename],
a1.rows as row_count,
(a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved,
a1.data * 8 AS data,
(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,
(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused
FROM
(SELECT
ps.object_id,
SUM (
CASE
WHEN (ps.index_id < 2) THEN row_count
ELSE 0
END
) AS [rows],
SUM (ps.reserved_page_count) AS reserved,
SUM (
CASE
WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
END
) AS data,
SUM (ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN
(SELECT
it.parent_id,
SUM(ps.reserved_page_count) AS reserved,
SUM(ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
WHERE it.internal_type IN (202,204)
GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2 ON ( a1.object_id = a2.object_id )
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
ORDER BY a3.name, a2.name
end try
begin catch
select
-100 as l1
, 1 as schemaname
, ERROR_NUMBER() as tablename
, ERROR_SEVERITY() as row_count
, ERROR_STATE() as reserved
, ERROR_MESSAGE() as data
, 1 as index_size
, 1 as unused
end catch
Try this:
Create a table (temp or otherwise) that mirrors the result set of the sproc. Then, in the body of your cursor, run this
INSERT INTO <tablename> EXEC sp_spaceused
after you close/deallocate the cursor, select from the table.