Tsql a way to find empty tables without using sys. Partitions - sql-server

Is there a way I can find all empty tables in a database without using sys. Partition rows?

You can use this query:
SELECT i.rowcnt, o.NAME
FROM sysindexes AS i
INNER JOIN sysobjects AS o ON i.id = o.id
WHERE i.indid < 2 AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0
AND i.rowcnt = 0
ORDER BY i.rowcnt desc

Related

Does a SELECT COUNT(*) query have to do a full table scan?

Does a query that gets the count of all rows in a table have to do a full table scan or does SQL Server maintain a count of rows somewhere?
SELECT COUNT(*) FROM TABLE_NAME;
The table TABLE_NAME has a primary key, and therefore a clustered index, and looks like so:
CREATE TABLE TABLE_NAME
(
Id int PRIMARY KEY IDENTITY(1, 1),
Name nvarchar(50) NOT NULL
);
I am using Microsoft SQL Server 2014.
The server will always read all records (if there's an index then it will scan the entire index) to count the rows. You can't escape this as long as you are doing SELECT COUNT(*) FROM Table.
If your table has a clustered index, you can change your query to an "under the hood" query to retrieve the count without actually fetching the records with:
SELECT OBJECT_NAME(i.id) [Table_Name], i.rowcnt [Row_Count]
FROM sys.sysindexes i WITH (NOLOCK)
WHERE i.indid in (0,1)
ORDER BY i.rowcnt desc
if you are looking for an approximate count of the records, you can also use the following query:
SELECT
TableName = t.NAME,
SchemaName = s.Name,
[RowCount] = p.rows,
TotalSpaceMB = CONVERT(DECIMAL(18,2), SUM(a.total_pages) * 8 / 1024.0),
UsedSpaceMB = CONVERT(DECIMAL(18,2), SUM(a.used_pages) * 8 / 1024.0),
UnusedSpaceMB = CONVERT(DECIMAL(18,2), (SUM(a.total_pages) - SUM(a.used_pages)) * 8 / 1024.0)
FROM
sys.tables t
INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE
t.NAME NOT LIKE 'dt%'
AND t.is_ms_shipped = 0
AND i.OBJECT_ID > 255
GROUP BY
t.Name,
s.Name,
p.Rows
ORDER BY
TotalSpaceMB DESC
This will show non-system tables with their calculated (not exact) row count and the sum of the sizes of their data (with any index they might have), relatively fast without retrieving the records.
When SQL Server performs a query like SELECT COUNT(*), SQL Server will use the narrowest non-clustered index to count the rows. If the table does not have any non-clustered index, it will have to scan the table.
If your table has a clustered index you can get your count even faster.
SELECT COUNT(*) FROM TABLE_NAME;
Does a full table scan.
For optimizations you can refer to this.
you can following way. it is better in performance I guess.
SELECT COUNT(1) FROM TABLE_NAME

Putting many tables in to one table in SQL Server?

I'm trying to insert the result from a query into a new table.
I'm using this query and want to gather the result into a single table.
The query (I found somewhere) looks like this:
USE [AdventureWorksDW2012]
SELECT
OBJECT_SCHEMA_NAME(T.[object_id],DB_ID()) AS [Schema],
T.[name] AS [table_name],
AC.[name] AS [column_name],
TY.[name] AS system_data_type,
AC.[max_length],
AC.[precision], AC.[scale],
AC.[is_nullable], AC.[is_ansi_padded]
FROM
sys.[tables] AS T
INNER JOIN
sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
INNER JOIN
sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id]
AND AC.[user_type_id] = TY.[user_type_id]
WHERE
T.[is_ms_shipped] = 0
ORDER BY
T.[name], AC.[column_id];
Try using an INTO clause like this:
USE [AdventureWorksDW2012]
SELECT OBJECT_SCHEMA_NAME(T.[object_id],DB_ID()) AS [Schema],
T.[name] AS [table_name], AC.[name] AS [column_name],
TY.[name] AS system_data_type, AC.[max_length],
AC.[precision], AC.[scale], AC.[is_nullable], AC.[is_ansi_padded]
INTO dbo.MyNewTable
FROM sys.[tables] AS T
INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
INNER JOIN sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id]
AND AC.[user_type_id] = TY.[user_type_id]
WHERE T.[is_ms_shipped] = 0
ORDER BY T.[name], AC.[column_id]
;
Use INTO clause as next:-
USE [AdventureWorksDW2012]
SELECT OBJECT_SCHEMA_NAME(T.[object_id],DB_ID()) AS [Schema],
T.[name] AS [table_name], AC.[name] AS [column_name],
TY.[name] AS system_data_type, AC.[max_length],
AC.[precision], AC.[scale], AC.[is_nullable], AC.[is_ansi_padded]
Into New_table -- this line is added.
FROM sys.[tables] AS T
INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id]
INNER JOIN sys.[types] TY ON AC.[system_type_id] = TY.[system_type_id] AND AC.[user_type_id] = TY.[user_type_id]
WHERE T.[is_ms_shipped] = 0
ORDER BY T.[name], AC.[column_id]
The sample code is
Select *
Into New_table
From Exist_Table
and as MSDN says:-
SELECT…INTO creates a new table in the default filegroup and inserts
the resulting rows from the query into it.

Query to return distinct values in fields containing string across multiple tables

The following query looks for fields within a db that contain '%string%' and returns them in a table with 5 columns; Schema, Table, Number of fields containing desired string in title of field within table, number of rows in table, and finally the field names.
SELECT s.name schemaName
, t.name tabName
, COUNT(c.name) OVER (PARTITION BY t.name ORDER BY t.name) totalColsWithString
, rc.row_count
, c.name colName
FROM sys.all_columns c
JOIN sys.tables t ON (t.object_id = c.object_id)
JOIN sys.schemas s ON (s.schema_id = t.schema_id)
LEFT JOIN
(
SELECT o.name
, ddps.row_count
FROM sys.indexes i
JOIN sys.objects o ON (i.object_id = o.object_id)
JOIN sys.dm_db_partition_stats AS ddps ON (i.object_id = ddps.object_id AND i.index_id = ddps.index_id)
WHERE i.index_id < 2 AND o.is_ms_shipped = 0
) rc ON (rc.name = t.name)
WHERE c.name LIKE '%String%'
AND row_count <> 0;
What I now want is a field that shows the number of distinct values in those fields which contain 'string' in the title (in all the columns returned in above query).
Does MS SQL Server store any info about distinct values in fields? Can it be made to?
Updated answer
You actually should consider to run 2 queries in that case. Or use subqueries, which may cause performance issues at a big dataset. Subqueries could look like this
SELECT [...],
(SELECT COUNT(*) FROM all_columns c2 WHERE c2.name= c.name) AS totalcolswithstring
FROM [...]
I set up a fiddle for you SqlFiddle

How can we check whether data exists or not in a table thru sys. tables/functions directly

Is there any way to check whether data exists in a table thru sys. tables or functions directly without querying the table.
Any such sys. available?
** Not querying the dynamic sql..:)
Read this article:
Find Row Count in Table – Find Largest Table in Database
Here is a query to find a ROWCOUNT of a table:
SELECT SUM(pa.rows) RowCnt
FROM sys.tables ta
INNER JOIN sys.partitions pa
ON pa.OBJECT_ID = ta.OBJECT_ID
WHERE ta.is_ms_shipped = 0
AND pa.index_id IN (1,0)
AND ta.name='table1'
SQLFiddle demo
Or if you need only information about empty table or not then something like this:
SELECT
ISNULL(
(SELECT TOP 1 1 from sys.partitions pa
where pa.OBJECT_ID = ta.OBJECT_ID
AND
pa.rows>0
AND
pa.index_id IN (1,0)
)
,0) as TableIsNotEmpty
FROM sys.tables ta
WHERE ta.is_ms_shipped = 0
AND ta.name='table1'
-- This is how I got the result...
SELECT Distinct tbl.name, C.name , X.rowcnt
FROM Sys.Columns as c
INNER JOIN Sys.Tables as tbl
ON tbl.object_id = c.object_id
INNER JOIN Sys.Types as t
ON c.system_type_id = t.system_type_id
INNER JOIN Sys.Indexes I
ON I.object_id = Tbl.object_id
Inner Join Sys.sysindexes X
On I.index_id = X.indid
And I.object_id = X.id
WHERE X.rowcnt > 0
ORDER BY tbl.name

when were index statistics last updated?

Is there a quick and easy way to list when every index in the database last had their statistics updated? The preferred answer would be a query. Also, is it possible to determine the "quality" of the statistics: FULLSCAN, SAMPLE n, etc.
EDIT
This worked for what I needed, a slight mod to #OrbMan great answer...
SELECT
STATS_DATE(i.object_id, i.index_id) AS LastStatisticsDate
,o.Name AS TableName
,i.name AS IndexName
FROM sys.objects o
INNER JOIN sys.indexes i ON o.object_id = i.object_id
WHERE o.is_ms_shipped=0
ORDER BY 1 DESC
You can do: STATS_DATE ( table_id , index_id )
So:
USE AdventureWorks;
GO
SELECT 'Index Name' = i.name, 'Statistics Date' = STATS_DATE(i.object_id, i.index_id)
FROM sys.objects o
JOIN sys.indexes i ON o.name = 'Address' AND o.object_id = i.object_id;
GO
where Address is the name of the table whose indexes you would like to examine.

Resources