T-SQL row count for each table with a WHERE - sql

I'm using SQL Server and have the below query to retrieve the RowCount of all tables that begin with 'IN%'. This works fine.
However, within each 'IN...' table there is a column called 'ErrorFlg' - this can be 0 or 1.
How do I modify the below to also include a new column called 'NoOfErrors' that will count where the 'ErrorFlg = 1' in each table?
SELECT
ta.name AS TableName,
SUM(pa.rows) AS RowCnt
FROM
sys.tables AS ta
INNER JOIN
sys.partitions AS pa ON pa.object_id = ta.object_id
INNER JOIN
sys.schemas AS sc ON ta.schema_id = sc.schema_id
WHERE
(ta.is_ms_shipped = 0) AND (pa.index_id IN (1, 0))
AND (ta.name LIKE 'IN_%')
GROUP BY
sc.name, ta.name
ORDER BY
TableName, RowCnt DESC
Ideal output:
TableName RowCnt NoOfErrors
--------------------------------
IN_123 100 50
IN_4566 500 2
IN_ABC 250 125

As per #Lamu's suggestion, The will create a table variable with your results and then create and execute dynamic statements...
Declare #Tbl Table
(
TableName VarChar(50),
RowCnt Int
)
Insert Into #Tbl
SELECT
ta.name AS TableName,
SUM(pa.rows) AS RowCnt
FROM
sys.tables AS ta
INNER JOIN
sys.partitions AS pa ON pa.object_id = ta.object_id
INNER JOIN
sys.schemas AS sc ON ta.schema_id = sc.schema_id
WHERE
(ta.is_ms_shipped = 0) AND (pa.index_id IN (1, 0))
AND (ta.name LIKE 'IN_%')
GROUP BY
sc.name, ta.name
ORDER BY
TableName, RowCnt DESC
Declare #tblname VarChar(50)
Declare #rowcnt VarChar(10)
Declare #vsql VarChar(Max) = NULL
Declare c Cursor For Select TableName,RowCnt From #Tbl
Open c
Fetch Next From c Into #tblname, #rowcnt
WHILE ##FETCH_STATUS = 0
BEGIN
Set #vsql = 'Select ''' + #tblname +''' As Tbl,''' + #rowcnt + ''' As RowCnt, Count(*) As NoOfErrors From ' + #tblname + ' Where ErrorFlg = 1'
Exec(#vsql)
Set #vsql = NULL
Fetch Next From c Into #tblname, #rowcnt
END

Related

Count rows in all tables, that meets conditions

I have database with 7,000 tables, most of these have a column DataAreaId, but not all tables, since some are global.
I would like to list all tables that have the column DataAreaId and their row count where the column DataAreaId contains "FR".
So for one table it would be:
SELECT COUNT(*)
FROM Table
WHERE DataAreaId = 'FR'
Any suggestions?
You can use the following
CREATE TABLE T1(
Dataareaid VARCHAR(45)
);
CREATE TABLE T2(
Dataareaid VARCHAR(45)
);
INSERT INTO T1 VALUES
('FR'),
('ALG'),
('FR');
DECLARE #SQL NVARCHAR(max) = N'';
SELECT #SQL = (
SELECT CONCAT(
N'UNION ALL ',
N'SELECT ''',
t.name,
N''' AS TableName, ',
N'Cnt = (SELECT COUNT(1)',
' FROM ',
QUOTENAME(t.name),
N' WHERE [Dataareaid] = ''FR'')'
)
FROM sys.columns c
JOIN sys.tables t ON c.object_id = t.object_id
WHERE c.name = 'Dataareaid'
FOR XML PATH('')
)
SET #SQL = STUFF(#SQL, 1, 10, N'');
EXEC sp_executesql #SQL;
Returns:
+-----------+-----+
| TableName | Cnt |
+-----------+-----+
| T1 | 2 |
| T2 | 0 |
+-----------+-----+
Live Demo
One way to do this is to query all tables containing that column, and build a query statement for each
select 'union all select ' + QUOTENAME(t.name,N'''') + ', count(1) from ' + t.name + ' where Dataareaid = ''FR'''
from sys.columns c
join sys.tables t ON c.object_id = t.object_id
where c.name = 'Dataareaid'
each row would look like this
union all select 'SomeTable', count(1) from SomeTable where Dataareaid = 'FR'
Now just put all statements together and remove the first union all
My answer gets the column metadata, executes the statement in a loop and publishes the results to a table variable:
if object_id('tempdb..#LoopList') is not null
drop table #LoopList
select
s.[name] as SchemaName
,t.[name] as TableName
,row_number() over (order by t.[object_id] asc) as RowNumber
into #LoopList
from sys.columns as c
inner join sys.tables as t
on c.[object_id] = t.[object_id]
inner join sys.schemas as s
on t.[schema_id] = s.[schema_id]
where c.[name] = 'Dataareaid'
declare
#a int = 1
,#b int = (select max(RowNumber) from #LoopList)
,#c nvarchar(max)
,#d nvarchar(max)
,#e int
declare #count table (RowCounter int)
declare #resultsTable table (TableName nvarchar(500), RowCounter int)
while #a <= #b
begin
delete from #count
set #c = concat ((select quotename(SchemaName) from #LoopList where RowNumber = #a)
,'.'
,(select quotename(TableName) from #LoopList where RowNumber = #a)
)
set #d = concat(N'select count(*) from '
,#c
,N' where Dataareaid = ''FR'''
)
insert into #count (
RowCounter
)
exec sp_executesql #d
set #e = (select top 1 RowCounter from #count)
insert into #resultsTable (
TableName
,RowCounter
)
values (#c,#e)
set #a += 1;
end
select * from #resultsTable

Query to find Size for each table By Filtering Rows

The Following Code will display the Size of each table in database
USE DatabaseName
GO
CREATE TABLE #temp (
table_name SYSNAME
, row_count INT
, reserved_size VARCHAR(50)
, data_size VARCHAR(50)
, index_size VARCHAR(50)
, unused_size VARCHAR(50)
)
SET NOCOUNT ON
INSERT #temp
EXEC sp_MSforeachtable 'sp_spaceused ''?'''
SELECT a.table_name
, a.row_count
, COUNT(*) AS col_count
, a.data_size
FROM #temp a
INNER JOIN INFORMATION_SCHEMA.columns b ON a.table_name COLLATE database_default
= b.table_name COLLATE database_default
GROUP BY a.table_name
, a.row_count
, a.data_size
ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS INTEGER) DESC
DROP TABLE #temp
Is there any way to Find the Space of All table by filtering the Row.
Like I have Foreign Key Company ID In All Table would it be possible if i want to know the space Occupied by Company
---Example ---
Purchase Table :
P_ID P_Description P_Price P_CompanyID
------------------------------------------
1 Mobile 100 1
2 Laptop 2100 1
3 Table 50 2
Sale table:
S_ID s_Description S_Price S_CompanyID
------------------------------------------
1 Mobile 110 1
2 Laptop 2200 1
3 Table 100 2
OutPut table:
Table Size Company
---------------------------------
Purchase 1.5MB 1
Sale 1.5MB 1
Purchase 1MB 2
Sale 1MB 2
I have Found the solution as per my Requirement. Thanks to Devart Help.
DECLARE #tblNAME NVARCHAR(50) = ''
DECLARE #colNAME NVARCHAR(50) = ''
DECLARE #SQL NVARCHAR(MAX) = ''
DECLARE CUR CURSOR FOR
SELECT NAME
FROM SYS.TABLES
WHERE TYPE = 'U'
AND SCHEMA_ID = 1
AND name NOT LIKE 'tt_%'
OPEN CUR
FETCH NEXT FROM CUR INTO #tblNAME
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #colNAME= c.name
FROM sys.columns c,sys.objects o
WHERE c.[object_id] = o.[object_id]
AND c.name like '%_CompanyID' And o.name=#tblNAME
if #colNAME is null or #colNAME =''
begin
FETCH NEXT FROM CUR INTO #tblNAME
end
Else
Begin
-- PRINT #tblNAME
--Print '---'+ #colNAME
SELECT #SQL += '
IF OBJECT_ID(''tt_' + o.name + ''') IS NOT NULL
DROP TABLE [tt_' + o.name + ']
SELECT *
INTO [tt_' + o.name + ']
FROM ' + QUOTENAME(SCHEMA_NAME(o.[schema_id])) + '.' + QUOTENAME(o.name) + '
WHERE '+#colNAME+' =10' -- your condition
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.name NOT LIKE 'tt_%'
AND o.name LIKE #tblNAME
AND o.is_ms_shipped = 0
AND EXISTS(
SELECT *
FROM sys.columns c
WHERE c.[object_id] = o.[object_id]
AND c.name like '%_CompanyID' -- your column
)
Set #colNAME=null
FETCH NEXT FROM CUR INTO #tblNAME
end
END
CLOSE CUR
DEALLOCATE CUR
Print #SQL
EXEC sys.sp_executesql #SQL
SELECT REPLACE(o.name, 'tt_', '') as TableName, t.Size, t.Total_Rows, '1' as IsClient
FROM sys.objects o
JOIN (
SELECT
i.[object_id]
, size = SUM(a.total_pages) * 8. / 1024
, total_rows = SUM(CASE WHEN i.index_id IN (0, 1) AND a.[type] = 1 THEN p.[rows] END)
FROM sys.indexes i
JOIN sys.partitions p ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
GROUP BY i.[object_id]
) t ON o.[object_id] = t.[object_id]
WHERE o.name LIKE 'tt_%'
AND o.is_ms_shipped = 0
AND o.[type] = 'U'
ORDER BY t.size DESC
SET #SQL = ''
SELECT #SQL += '
DROP TABLE [' + o.name + ']'
FROM sys.objects o
WHERE o.[type] = 'U'
AND o.name LIKE 'tt_%'
AND o.is_ms_shipped = 0
EXEC sys.sp_executesql #SQL

SQL server 2012 select row counts from a variable number of tables

I have the following query
select count(*) as row_count
, UN_PART
, 'ABC_PARAM_DETA' as TABLE_NAME
from ABC_PARAM_DETA
group by UN_PART
what I would like to do is extend this to use it from a select list rather than a single table as I have multiple tables with UN_PART eg
select count(*) as row_count
, UN_PART
, '#var_table' as TABLE_NAME
from (Select TABLE_NAME from INFORMATION_SCHEMA.COLUMNS where COLUMN_NAME = 'UN_PART')
group by UN_PART
Anyone any ideas on how to achieve this
Try this
IF OBJECT_ID('tempdb..#Output') IS NOT NULL
DROP TABLE #Output
CREATE TABLE #Output
(ID INT IDENTITY(1, 1),
TableName NVARCHAR(MAX),
RowCnt INT)
INSERT INTO #Output (TableName)
Select C.TABLE_NAME from INFORMATION_SCHEMA.COLUMNS C
INNER JOIN INFORMATION_SCHEMA.TABLES T ON C.TABLE_NAME = T.TABLE_NAME
WHERE COLUMN_NAME = 'UN_PART' AND T.TABLE_TYPE = 'BASE TABLE'
DECLARE #Step AS INT = 1
WHILE #Step <= (SELECT COUNT(*) FROM #Output) BEGIN
DECLARE #TableName NVARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
SELECT #TableName = TableName FROM #Output WHERE ID = #Step
SET #SQL = 'UPDATE #Output SET RowCnt = (SELECT COUNT(*) FROM ' + #TableName + ') WHERE TableName = ''' + #TableName + ''''
EXEC sys.sp_executesql #SQL
SET #Step = #Step + 1
END
SELECT * FROM #Output
DROP TABLE #Output
Haven't tested but I think this should work
Exec sp_MSforeachtable
#command1 ='select ''?'', un_part, count(1) from ? group by un_part'
,#whereand = ' and object_id in (select o.object_id from sys.objects o
inner join sys.columns c
on o.object_id = c.object_id
and c.name = ''UN_PART'')'

List columns in a table with associated values for one record

I am building a query which should list all columns in a table along with a data sample for each column name. For example, if I had a table called 'person' with the columns of 'first', 'last' and 'age', I would need it listed like this:
table_name column_name column_value
person person_id 443
person first john
person last smith
person age 48
The goal of this query is to actually list all columns in any given table - I have this working. I want to have a data value listed in the third column (column_value) so I can check the front end of applications against the backend and ensure I am actually dealing with the correct column.
This table may have hundreds or thousands of records, but I am just trying to pull one matching record. The average table columns I am working with in any given table is 200+, so I can't do this by hand.
Here is the query I am using to pull all columns from a table:
SELECT table_name
, COLUMN_NAME
, '' AS column_value
FROM information_schema.COLUMNS
WHERE TABLE_NAME LIKE '%person%'
ORDER BY TABLE_NAME
This query returns the following results (notice column_value is empty):
table_name column_name column_value
person person_id
person first
person last
person age
I will use the unique primary key to identify a single person record to pull from - this will ensure I don't have repeated column names (ex. person_id/first/last/age repeating for each time a person is pulled.)
The question is, how do I turn this into a list of columns along with the value of a specific selected record in the 'column_value' column??
UPDATE
Just to clarify, I am basically trying to turn this type of query & output:
SELECT * FROM person WHERE person_id = 443;
** outputs this:
person_id first last age
443 john smith 48
Into this:
table_name column_name column_value
person person_id 443
person first john
person last smith
person age 48
You could try something like this
DECLARE #SchemaName sysname
DECLARE #TableName sysname
DECLARE #Colname sysname
DECLARE #SQL_Template nvarchar(max)
DECLARE #SQL nvarchar(max)
SET #SchemaName = 'Sales'
SET #TableName = 'Customer'
CREATE TABLE ##Results(Colname sysname, colvalue varchar(256))
SET #SQL_Template = 'INSERT INTO ##Results(Colname,colvalue ) SELECT top 1 ''#Colname '' as Colname,'
+ ' CONVERT(nvarchar(256),#Colname) AS ColValue'
+ ' FROM ['+#SchemaName+'].['+#TableName+']'
DECLARE COL_CURSOR CURSOR STATIC FOR
SELECT c.name
FROM sys.schemas s
JOIN sys.tables t ON t.schema_id = s.schema_id
JOIN sys.columns c ON c.object_id = t.object_id
WHERE s.name = 'Sales' AND t.name = 'Customer'
OPEN COL_CURSOR
FETCH NEXT FROM COL_CURSOR INTO #Colname
WHILE ##FETCH_STATUS =0
BEGIN
SET #SQL = REPLACE(#SQL_Template,'#ColName',#ColName)
PRINT #SQL
EXEC sp_executesql #SQL
FETCH NEXT FROM COL_CURSOR INTO #Colname
END
CLOSE COL_CURSOR
DEALLOCATE COL_CURSOR
SELECT * FROM ##Results
DROP TABLE ##Results
I have created this procedure which will take Table Name as Parameter and returns the information you have asked for.
CREATE PROCEDURE usp_GetTableFormat_And_SampleDate
#TableName NVARCHAR(128)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #ColsCasted NVARCHAR(MAX);
DECLARE #Cols NVARCHAR(MAX);
SELECT #TableName = t.name
, #ColsCasted = STUFF(( SELECT ', CAST(' + QUOTENAME(sc.name) + ' AS NVARCHAR(1000)) AS ' + QUOTENAME(sc.name)
FROM sys.tables st INNER JOIN sys.columns sc
ON st.object_id = sc.object_id
WHERE st.name = #TableName
AND st.object_id = t.object_id
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1 ,2 ,'')
FROM sys.tables t
WHERE t.name = #TableName
GROUP BY t.name, t.object_id
SELECT #TableName = t.name
, #Cols = STUFF(( SELECT ', ' + QUOTENAME(sc.name)
FROM sys.tables st INNER JOIN sys.columns sc
ON st.object_id = sc.object_id
WHERE st.name = #TableName
AND st.object_id = t.object_id
FOR XML PATH(''),TYPE)
.value('.','NVARCHAR(MAX)'),1 ,2 ,'')
FROM sys.tables t
WHERE t.name = #TableName
GROUP BY t.name, t.object_id;
DECLARE #Sql NVARCHAR(MAX);
SET #Sql =
N'WITH CTE AS
(
SELECT * FROM (
SELECT TOP 1 ' + #ColsCasted + N'
FROM ' + QUOTENAME(#TableName) + N') Q
UNPIVOT ( VALS for N IN (' + #Cols + '))up
)
SELECT TableName
, ColName AS ColumnName
, VALS AS SampleData
FROM CTE C INNER JOIN
(SELECT sc.Name AS ColName, st.Name AS TableName FROM sys.tables st INNER JOIN sys.columns sc
ON st.object_id = sc.object_id WHERE st.name = '''+ #TableName + N''' ) Q2
ON C.N = Q2.ColName'
EXECUTE sp_executesql #Sql
END
Test
I have a table called 'Department' in my database
EXECUTE usp_GetTableFormat_And_SampleDate 'Department'
Result Set
╔════════════╦════════════╦════════════╗
║ TableName ║ ColumnName ║ SampleData ║
╠════════════╬════════════╬════════════╣
║ Department ║ DeptID ║ 1 ║
║ Department ║ Department ║ HR ║
╚════════════╩════════════╩════════════╝
If it's only a few tables that you have to do then you can bundle it up into a union query along the lines of
CREATE PROC sp_person_values (#PersonID int)
AS
BEGIN
SELECT 'person_id' As ColumnName, CONVERT(varchar(256),person_id) As ColumnValue FROM person WHERE person_id = #PersonID
UNION ALL
SELECT 'first' As ColumnName, CONVERT(varchar(256),first) As ColumnValue FROM person WHERE person_id = #PersonID
UNION ALL
SELECT 'last' As ColumnName, CONVERT(varchar(256),last) As ColumnValue FROM person WHERE person_id = #PersonID
UNION ALL
SELECT 'age' As ColumnName, CONVERT(varchar(256),age) As ColumnValue FROM person WHERE person_id = #PersonID
END

Constructing the FROM in SQL

I'm looking to pull a specific line from a number of table that have a field name criteria1. The problem I'm having is that when I combine the Owner and Table Name and try to call "select criteria1 from #t where linenum = 1" SQL is expecting #t to be a table. I need to know how to construct the full table name and then pass it to this query. I know I can us a programming language to access the DB but i need this to be in SQL. If someone knows of a better way of doing this that would be great too.
declare #next as varchar
declare #owner varchar
while 1=1
begin
set #next = (select top 1 o.name FROM syscolumns c inner join sysobjects o on c.id = o.id
where c.name = 'criteria1' and o.id > #next order by o.id)
if #next is null
break
else
begin
set #owner = (select top 1 u.name
FROM syscolumns c inner join
sysobjects o on c.id = o.id left join
sysusers u on o.uid=u.uid
where c.name = 'criteria1' and o.id = #next order by o.id)
declare #t as varchar
set #t = #owner+'.'+#next
select criteria1 from #t where linenum = 1
end
continue
end
You can build the entire query you want as a varchar() and then execute it with the sp_executesql stored procedure.
http://msdn.microsoft.com/en-us/library/ms188001.aspx
In your case, that bit at the end becomes
declare #sql varchar(512);
set #sql = 'select criteria1 from ' + #t + ' where linenum = 1'
sp_executesql #sql
Have you considered the following construct in a stored procedure?
CASE #tablename
WHEN 'table1' THEN SELECT * FROM table1
WHEN 'table2' THEN SELECT * FROM table2
WHEN 'table3' THEN SELECT * FROM table3
WHEN 'table4' THEN SELECT * FROM table4
END
In case you're married to dynamic SQL (considered to be a bad choice for this problem space), this guide to dynamic SQL should help a lot. It helped me and I've used dynamic SQL extensively.
Thanks for all the help. This is what I ended up with.
declare cur cursor for
select u.name + '.' + o.name tname
FROM sysobject o left join
syscolumns c on c.id = o.id left join
sysusers u on o.uid=u.uid
where c.name = 'criteria1'
declare #tn as varchar(512)
open cur
fetch next from cur into #tn
create table holding_table ( val varchar(512), table_name varchar(512))
declare #sql nvarchar(1000)
while ##FETCH_STATUS = 0
begin
set #sql = 'insert into holding_table select criteria1, ''' + #tn + ''' from ' + #tn + ' where linenum = 1'
execute sp_executesql #sql
fetch next from cur into #tn
end
close cur
deallocate cur
Maybe a view can be used here?
CREATE VIEW vCriterias
AS
SELECT 'Table1' AS TableName,
linenum,
criteria1
FROM Table1
UNION ALL
SELECT 'Table2' AS TableName,
linenum,
criteria1
FROM Table2
UNION ALL
SELECT 'Table3' AS TableName,
linenum,
criteria1
FROM Table3
go
Then selection is like:
SELECT criteria1
FROM vCriterias
WHERE linenum = 3
AND TableName IN ('Table1','Table3')