I have a list of tables across multiple databases, and I would like to find out the row counts for these tables and the name of these tables.
Note that the names of the tables may change, as I need to repeat this many times, so ideally, I would like to specify the tables and then query some of the data dictionary tables.
I am able to achieve what I want, by writing multiple queries for each database and then sticking the results into one final table, but wondered if there is a solution that is more elegant.
Below is an example that will get the row counts for all tables in the specified databases in a single resultset. Add additional filters as appropriate for your needs.
DECLARE #SQL nvarchar(MAX) =
STUFF((SELECT N'UNION ALL SELECT
N''' + QUOTENAME(d.name) + N'''
+ N''.''
+ QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id, ' + CAST(d.database_id AS nvarchar(10)) + N'))
+ N''.''
+ QUOTENAME(t.name) AS TableName
, SUM(p.rows) AS Rows
FROM ' + QUOTENAME(d.name) + N'.sys.tables AS t
JOIN ' + QUOTENAME(d.name) + N'.sys.partitions AS p ON p.object_id = t.object_id AND p.index_id IN(0,1)
GROUP BY N''' + QUOTENAME(d.name) + N'''
+ N''.''
+ QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id, ' + CAST(d.database_id AS nvarchar(10)) + N'))
+ N''.''
+ QUOTENAME(t.name)'
FROM sys.databases AS d
WHERE d.name IN(N'Database1', N'Database2)
FOR XML PATH(''), TYPE).value('(text())[1]','nvarchar(MAX)'),1,10,'');
EXEC sp_executesql #SQL;
You can get the number of rows using system tables as well. If you need other tables from different databases as well, you can just use union and Change Adventure works to your DB name.
select t.name as Tablename, s.name Schemaname ,p.rows as Numberofrows from AdventureWorks.sys.tables t
join AdventureWorks.sys.schemas s on t.schema_id = s.schema_id
join AdventureWorks.sys.indexes i on i.object_id = t.object_id
join AdventureWorks.sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id
group by t.name , s.name ,p.rows
Output:
Related
I found this useful query to rename all my tables, indexes and constrains but I just figured out it didn't rename the columns.
SELECT 'exec sp_rename ' + '''' + NAME + '''' + ', ' + '''' + replace(NAME, 'Tb', 'Tabela') + ''''
FROM sysObjects
WHERE
NAME LIKE 'Tb%'
I know there's syscolumns but I'm not sure how to use in this case.
Question: How can I get the same result of this query but for columns instead of tables?
I appreciate your help in this. I'm using SQL Server 2012. Thanks.
You have to do a little more work:
SELECT 'exec sp_rename ' + '''' + QUOTENAME(s.name) + '.' + QUOTENAME(o.name) + '.' + QUOTENAME(c.name) + '''' + ', ' + '''' + replace(c.name, 'Col', 'Column') + ''', ''COLUMN'''
FROM sys.columns c
INNER JOIN sys.objects o ON c.object_id = o.object_id
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
WHERE c.name LIKE 'Col%'
Since you are renaming column, you must specify that third argument to sp_rename is COLUMN. You must also construct three part name in the form of [schema].[table name].[current column name] to point to the correct column.
I'm trying to retrieve all primary keys iin a fact table and then count the number of records in that fact table grouped by that id, however so far i can only seem to get all the primary keys and its talbe. i guess i need to make some kind of subquery
SELECT
tab1.name AS [FactTable],
col1.name AS [PrimaryKey]
FROM sys.indexes ind1
INNER JOIN sys.tables tab1
ON tab1.object_id = ind1.object_id
INNER JOIN sys.schemas sch1
ON tab1.schema_id = sch1.schema_id
INNER JOIN sys.columns col1
ON col1.object_id = tab1.object_id AND col1.name like '%Id'
WHERE tab1.name like 'Fact%' AND ind1.is_primary_key = 1
sample output
primaryKey countRecordsGroupedByPrimaryKey
2 4000
3 8343
4 203
1 4023
I going out on a limb and guessing that you want to count the number of each dimensionPK used in your fact table. If a fact table has references to two different dimensions, you need two different statements to count the usage by that dimension.
For the query below, provide your fact table name and schema and it should generate a count statement joining your fact and dim and grouping by the join keys.
- If a fact table has two different FK relationships, you'll get two different statements.
- If a table uses a composite PK, both key columns will be included in the join
This is complicated and I don't have any tables with multiple FKs to test it on, so please let me know if it does what you want.
DECLARE #NameOfTableWithFKs sysname = 'your fact table name',
#SchemaOfTableWithFKs sysname = 'dbo';
WITH JoinColumns
AS (SELECT QUOTENAME(OBJECT_SCHEMA_NAME(parent.object_id)) + '.' + QUOTENAME(OBJECT_NAME(parent.object_id)) AS ParentTableName,
QUOTENAME(OBJECT_SCHEMA_NAME(referenced.object_id)) + '.' + QUOTENAME(OBJECT_NAME(referenced.object_id)) AS ReferencedTableName,
QUOTENAME(OBJECT_NAME(parent.object_id)) + '.' + QUOTENAME(parent.name) + ' = ' + QUOTENAME(OBJECT_NAME(referenced.object_id)) + '.'
+ QUOTENAME(referenced.name) AS JoinColumn,
QUOTENAME(OBJECT_NAME(referenced.object_id)) + '.' + QUOTENAME(referenced.name) AS GroupingColumn
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.columns AS parent
ON parent.object_id = fkc.parent_object_id
AND parent.column_id = fkc.parent_column_id
INNER JOIN sys.columns AS referenced
ON referenced.object_id = fkc.referenced_object_id
AND referenced.column_id = fkc.referenced_column_id
WHERE OBJECT_NAME(parent.object_id) = #NameOfTableWithFKs
AND OBJECT_SCHEMA_NAME(parent.object_id) = #SchemaOfTableWithFKs
),
JoinTables
AS (SELECT QUOTENAME(OBJECT_SCHEMA_NAME(tbl.object_id)) + '.' + QUOTENAME(OBJECT_NAME(tbl.object_id)) AS ParentTableName,
QUOTENAME(OBJECT_SCHEMA_NAME(rtbl.object_id)) + '.' + QUOTENAME(OBJECT_NAME(rtbl.object_id)) AS ReferencedTableName
FROM sys.tables AS tbl
INNER JOIN sys.foreign_keys AS cstr
ON cstr.parent_object_id = tbl.object_id
INNER JOIN sys.tables AS rtbl
ON rtbl.object_id = cstr.referenced_object_id
WHERE OBJECT_NAME(tbl.object_id) = #NameOfTableWithFKs
AND OBJECT_SCHEMA_NAME(tbl.object_id) = #SchemaOfTableWithFKs
)
SELECT 'SELECT Count(*)' + ( SELECT ', ' + JC.GroupingColumn
FROM JoinColumns AS JC
WHERE JC.ParentTableName = jt.ParentTableName
AND JC.ReferencedTableName = jt.ReferencedTableName
FOR XML PATH('')
) + ' FROM ' + JT.ParentTableName + ' INNER JOIN ' + JT.ReferencedTableName + ' ON'
+ SUBSTRING(( SELECT ' AND ' + JC.JoinColumn
FROM JoinColumns AS JC
WHERE JC.ParentTableName = JT.ParentTableName
AND JC.ReferencedTableName = JT.ReferencedTableName
FOR XML PATH('')
), 5, 8000
) + ' GROUP BY ' + SUBSTRING(( SELECT ', ' + JC.GroupingColumn
FROM JoinColumns AS JC
WHERE JC.ParentTableName = JT.ParentTableName
AND JC.ReferencedTableName = JT.ReferencedTableName
FOR XML PATH('')
), 2, 8000
)
FROM JoinTables AS JT;
If I understand the question correctly you are wanting to count all the rows in some tables based on some criteria. Not really sure why you care about the primary key portion since by definition a primary key must be unique so this could still be simplified to not check for primary key but whatever.
I did remove the join to sys.columns because why does it matter the name of the column unless you want only those table named Fact% and has a column named %Id.
This should get you pretty close as I understand it.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'select TableName = ''' + tab1.name + ''', NumRows = count(*) from ' + QUOTENAME(sch1.name) + '.' + QUOTENAME(tab1.name) + ' UNION ALL '
FROM sys.indexes ind1
INNER JOIN sys.tables tab1
ON tab1.object_id = ind1.object_id
INNER JOIN sys.schemas sch1
ON tab1.schema_id = sch1.schema_id
--INNER JOIN sys.columns col1
-- ON col1.object_id = tab1.object_id AND col1.name like '%Id'
WHERE tab1.name like 'Fact%'
AND ind1.is_primary_key = 1
select #SQL = LEFT(#SQL, LEN(#SQL) - 10) + ' ORDER BY TableName'
select #SQL --uncomment the exec line below once you are comfortable that the dynamic sql is what you want.
--exec sp_executesql #SQL
I have an application on vb.net that use a Sql server Database.
I'm using Entity Framework 6.1
The database has a lot's of tables (100+)
-On some tables there's a field "DelDate" (Date)
-On some tables there's a field "DelChilds" (Bit)
Is there a short way to do these operations :
1) Delete all records from all tables that have the DelDate= "01/01/2014"
2) Update the "DelChilds" field on all the records ( for example set to True )
Thank you !
You can write a Dynamic Query using sys.column and sys.tables and execute them in a batch .
You can call Stored Procedure to achieve this functionality using entity framework .
Procedure Code
Create Procedure UpdateDelete #date Date = '01/01/2014'
AS
Begin
Declare #DelQuery Nvarchar(Max),#updatequery Nvarchar(Max),
select #DelQuery = Stuff( (
select ' Delete from ' + t.name + ' where DelDate = ''' + Convert ( varchar,#date,110) + ''';' from sys.columns C JOIN sys.tables t on c.object_id = t.object_id
where C.name = 'DelDate' for XMl Path('')),1,1,'')
select #DelQuery
Exec sp_executeSQL #DelQuery
select #updatequery = Stuff( (
select ' UPDATE ' + t.name + ' SET DelChilds = 1 ;' from sys.columns C JOIN sys.tables t on c.object_id = t.object_id
where C.name = 'DelChilds' for XMl Path('')),1,1,'')
--select #updatequery
Exec sp_executeSQL #updatequery
END
For DelDate
select 'DELETE FROM ' + t.name + ' WHERE DelDate = ''01/01/2014'' ' + Char(13) + 'GO ' from sys.columns C JOIN sys.tables t on c.object_id = t.object_id
where C.name = 'DelDate'
For Delchilds
select 'UPDATE ' + t.name + ' SET DelChilds = 1 ' + Char(13) + 'GO ' from sys.columns C JOIN sys.tables t on c.object_id = t.object_id
where C.name = 'DelChilds'
Using a single select query, I need to get the Minimum and Maximum values of Identity Columns along with the other columns specified in the query below, for all tables in a given database.
This is what I've been able to code to get a list of tables and their identity columns:
Select so.name as TableName
, sic.name as ColumnName
, i.Rows Count_NumberOfRecords
, IDENT_CURRENT(so.name)+IDENT_INCR(so.name) as NextSeedValue
from sys.identity_columns sic
inner join sys.objects so on sic.object_id = so.object_id
inner join sys.sysindexes I ON So.OBJECT_ID = I.ID
Where so.type_desc = 'USER_TABLE' and last_value is not null and indid IN (0,1);
The query needs to get these extra columns:
MaximumValue (IdentityColumn) and MinimumValue (IdentityColumn) for each table.
You should be able to use something along these lines:
DECLARE #cmd NVARCHAR(max);
SET #cmd = '';
SELECT #cmd = #cmd + CASE WHEN (#cmd = '') THEN '' ELSE ' UNION ALL ' END + 'SELECT ''' +
QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ''' AS TableName, ''' +
QUOTENAME(c.name) + ''' AS ColumnName, MAX(' + QUOTENAME(c.name) + ') AS MaxID, MIN(' +
QUOTENAME(c.name) + ') AS MinID, COALESCE(IDENT_CURRENT(''' + QUOTENAME(s.name) + '.' +
QUOTENAME(t.name) + '''),0) + COALESCE(IDENT_INCR(''' + QUOTENAME(s.name) + '.' +
QUOTENAME(t.name) + '''),0) AS NextValue FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name)
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
INNER JOIN sys.schemas s on t.schema_id = s.schema_id
WHERE c.is_identity = 1
SELECT #cmd; /* Shows the dynamic query generated, not necessary */
EXEC sp_executesql #cmd;
The query uses dynamic SQL to construct a UNION query that gathers the Table Name, Column Name, and Min and Max ID values currently in every table that has an IDENTITY field.
You could quite easily modify this to show the columns in the format you want, along with the other columns you mention in your question.
I've edited the query above to include the "NextValue" field, however I agree with #AaronBertrand in that this value is of little use, since in a busy system it will most certainly be wrong immediately (or shortly thereafter) once the query executes.
My goal is to write a SQL Server script (2008 R2 if it matters) that nulls out all values in all tables where the column name contains "Qualifiers".
E.g. Table A contains columns named "TemperatureQualifiers" and "SalinityQualifiers". For all rows in that table, those values should be set to null. There are also several other tables that have columns with similar names.
This will generate the update statements for you. You can extend this to execute them as dynamic SQL or simply cut/paste the results to another SSMS query window and run them.
select 'update [' + s.name + '].[' + t.name + '] set [' + c.name + '] = NULL'
from sys.columns c
inner join sys.tables t
on c.object_id = t.object_id
inner join sys.schemas s
on t.schema_id = s.schema_id
where c.name like '%Qualifiers%'
and t.type = 'U'
Bit late on this one. This will generate a script that consolidates updates where there are multiple columns in the same table to be updated.
DECLARE #Script nvarchar(MAX);
SET #Script = '';
WITH Cols AS
( SELECT c.object_id,
c.name,
schema_name(t.schema_id) AS SchemaName,
t.name AS TableName
FROM sys.columns c INNER JOIN
sys.tables t ON c.object_id = t.object_id
WHERE c.name LIKE '%Qualifiers%'
AND is_computed=0
AND is_rowguidcol=0
AND is_identity=0
AND is_nullable=1
AND objectproperty(c.object_id, N'IsUserTable')=1
)
,
Tables AS
( SELECT DISTINCT object_id, TableName, SchemaName
FROM Cols
)
,
Statements AS
( SELECT 'UPDATE ' + QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName) + ' SET ' + STUFF(
( SELECT ',' + c.name + '=NULL'
FROM Cols c
WHERE c.object_id = t.object_id FOR XML PATH('')
)
, 1, 1, '') AS Statement
FROM Tables t
)
SELECT #Script = #Script + '
' +Statement
FROM Statements
SELECT #Script AS [processing-instruction(x)] FOR XML PATH('')