I have a table (DB_TableInfo) in my DB like the following
TableId Type
859374678 R
579845658 B
478625849 R
741587469 E
.
.
.
this table represents all tables in my DB. What I wanna do is to write a query to select tables of Type 'R', get their Id and return the Name of the table belonging to that Id (the TableName column is not available in the specified table)
Can anybody help me out?
I wanna write a query similar to this one!
SELECT TableID = OBJECT_NAME FROM [DB_TableInfo] WHERE Type = 'R'
From the mention of sys.objects and use of square brackets I assume you are on SQL Server.
You can use the object_name function.
SELECT OBJECT_NAME(TableID) /*Might match objects that aren't tables as well though*/
FROM [DB_TableInfo]
WHERE Type = 'R'
Or join onto sys.tables
SELECT T.name
FROM [DB_TableInfo] D
join sys.tables T ON D.TableID = T.object_id
WHERE D.Type = 'R'
And to exclude empty tables
SELECT t.name
FROM DB_TableInfo d
JOIN sys.tables t ON d.TableId = t.object_id
JOIN sys.dm_db_partition_stats ps ON ps.object_id = t.object_id
WHERE d.Type = 'R' and ps.index_id <= 1
GROUP BY d.TableId, t.name
HAVING SUM(ps.row_count) > 0
Related
I have a DB with lots of tables without use. I'd like to filter out the tables without any data. So I used a snippet How to fetch the row count for all tables by #ismetAlkan.
However, I want to filter out 0, so used something like this and it doesn't work.
USE [my_db]
GO
SELECT * FROM
(
SELECT SCHEMA_NAME(A.schema_id) + '.' +
A.Name, SUM(B.rows) AS 'RowCount'
FROM sys.objects A
INNER JOIN sys.partitions B ON A.object_id = B.object_id
WHERE A.type = 'U'
GROUP BY A.schema_id, A.Name
) AS Result
where Result.RowCount > 0
GO
Any help appreciated!
There are three problems.
SELECT * FROM
(
SELECT ObjectName = SCHEMA_NAME(obj.[schema_id])
+ '.' + obj.name,
[RowCount] = SUM(p.rows)
FROM sys.objects AS obj
INNER JOIN sys.partitions AS p
ON obj.[object_id] = p.[object_id]
WHERE obj.type = 'U'
GROUP BY obj.[schema_id], obj.name
) AS Result
WHERE Result.[RowCount] > 0;
When you move a query into a derived table, subquery, or CTE, all of the columns need to have names.
'Alias' should be [Alias] since the former makes it look like a string and that form is deprecated in some contexts.
As Larnu pointed out, ROWCOUNT needs to be escaped in all spots, not just one.
I am working on a project to document the tables in a database. One of the features I would like to include is a meta-table that includes some facts and statistics for every column in the table. I already have a query that does the following:
Column
Data Type
Nullable
Primary Key
Foreign Key
Col A
string
N
PK
Col B
string
N
FK
Etc.....
I would also like to get some common statistics of each column as either another table (or preferably as part of the above table) that would look like:
Column
Min
Max
Count
Count Distinct
Col A
1
486842
486842
486842
Col B
1
756
486842
395
Col C
1
5
210523
3
Perhaps also "Most Common Value" and "# of Most Common Value". Basic information that will give me a quick idea as to the distribution and uniqueness of values in a column. The calculations aren't the hard part. I don't understand how to connect actual tables to meta data. It also has a confusing back-and-forth pivot aspect.
Can this be done dynamically without typing out each and every column?
The following query produces the first table:
select
col.name as column_name,
t.name as data_type,
case when col.is_nullable = 0 then 'N'
else 'Y' end as nullable,
case when pk.column_id is not null then 'PK'
else '' end as primary_key,
case when fk.parent_column_id is not null then 'FK'
else '' end as foreign_key
from sys.tables as tab
left join sys.columns as col
on tab.object_id = col.object_id
left join sys.types as t
on col.user_type_id = t.user_type_id
left join (
select index_columns.object_id,
index_columns.column_id
from sys.index_columns
inner join sys.indexes
on index_columns.object_id = indexes.object_id
and index_columns.index_id = indexes.index_id
where indexes.is_primary_key = 1
) as pk
on col.object_id = pk.object_id
and col.column_id = pk.column_id
left join (
select fc.parent_column_id,
fc.parent_object_id
from sys.foreign_keys as f
inner join sys.foreign_key_columns as fc
on f.object_id = fc.constraint_object_id
group by fc.parent_column_id, fc.parent_object_id
) as fk
on fk.parent_object_id = col.object_id
and fk.parent_column_id = col.column_id
where tab.name = 'table_products'
order by primary_key desc, foreign_key desc, nullable asc, column_name asc;
Edit: Solved via comments showing that SQL Server Column Statistics already provide this type of information.
I need to create some statistics on a table with different combination of columns. But there may be already some statistic exist with same combination of columns. So, Before creating a statistic with a combination of columns, I want to check if there exists any statistic with same combination of columns. If exist then I will not create the statistic and if not exist then only I will create the statistic.
For example create a table and a statistic on this table as following:
CREATE TABLE Gift
(
Gift_Id INTEGER IDENTITY (1,1) PRIMARY KEY,
Person_Id INTEGER,
Event_Id INTEGER,
Agent_Id INTEGER,
Fund_Id INTEGER,
Amount FLOAT
)
CREATE STATISTICS [Stats1_1_2_3]
ON [dbo].[Gift]([Gift_Id], [Person_Id], [Event_Id])
So we have a table Gift and a statistic with columns Gift_ID, Person_Id and Event_Id.
Now If I create another statistic as following:
CREATE STATISTICS [Stats2_1_2_3]
ON [dbo].[Gift]([Gift_Id], [Person_Id], [Event_Id])
See later statistic is duplicate of first statistic (With same columns).
So, to avoid the duplication, I need to check if there exists any statistic with same columns.
Is there any way to do this?
Please help
The below query will check the sys.stats,sys.stats_columns and sys.columns table to find all statistics for the given table and get each column for each statistic.
The grouping and counting is to check if one statistic exists that refers to all columns.
Note that the query mentions explicitly the table name, the column names and the number of columns that is being checked.
The updated query also checks if ONLY the columns listed are present (counting = 3) and ALL the columns listed are present (counting3 = 3). Use for other statistics will involve modifications for the CASE statement and the '3' values in the last WHERE line.
SELECT * FROM (
SELECT s.name AS statistics_name,
count(*) as counting,
sum(case
when c.name = 'Gift_Id' then 1
when c.name = 'Person_Id' then 1
when c.name = 'Event_Id' then 1
else 0
end) as counting3
FROM sys.stats AS s
INNER JOIN sys.stats_columns AS sc
ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id
INNER JOIN sys.columns AS c
ON sc.object_id = c.object_id AND c.column_id = sc.column_id
WHERE s.object_id = OBJECT_ID('Gift')
Group by s.name) T
WHERE T.COUNTING = 3 AND T.COUNTING3 = 3;
Updated SQLFiddle for the above
Following query will give the name of the statistic (If any exists) with the given combination of the columns.
SELECT s.name
FROM sys.stats s inner join
sys.stats_columns sc on s.stats_id = sc.stats_id and s.object_id = sc.object_id
JOIN sys.columns c ON c.[object_id] = sc.[object_id] AND c.column_id = sc.column_id
WHERE OBJECT_NAME(s.OBJECT_ID) = 'Gift'
and s.stats_id not in
(
SELECT distinct s.stats_id
FROM sys.stats s inner join
sys.stats_columns sc on s.stats_id = sc.stats_id and s.object_id = sc.object_id
JOIN sys.columns c ON c.[object_id] = sc.[object_id] AND c.column_id = sc.column_id
WHERE OBJECT_NAME(s.OBJECT_ID) = 'Gift' and c.name not in ('Gift_Id','Person_Id','Event_Id')
)
group by s.name
having count(1)= 3
Updated SQLFiddle for the above
I have a database and a lot of tables inside it. I wrote some information into the each table and column's decription part. And now using query i want to see all table and columns descriptions.
Note: DATABASE -> ms sql server
Can you please help me ?
You can see that using INFORMATION_SCHEMA
To get columns for each table you can do:
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
To get table information you can do:
SELECT * FROM INFORMATION_SCHEMA.TABLES
Check this query:
SELECT
t.name AS TableName
, td.value AS TableDescription
, c.name AS ColumnName
, cd.value AS ColumnDescription
FROM sys.tables t
INNER JOIN sys.columns c ON t.object_id = c.object_id
LEFT JOIN sys.extended_properties td
ON td.major_id = t.object_id
AND td.minor_id = 0
AND td.name = 'MS_Description'
LEFT JOIN sys.extended_properties cd
ON cd.major_id = t.object_id
AND cd.minor_id = c.column_id
AND cd.name = 'MS_Description'
select * from INFORMATION_SCHEMA.TABLES
select * from INFORMATION_SCHEMA.COLUMNS
select * from user_col_comments;
This will display all tables's column with comments for the logged in user.
select * from user_col_comments where table_name = '<table name>';
This will display specified tables's column with comments for the logged in user.
desc table_name query is used to describe the table
I have database A which contains a table (CoreTables) that stores a list of active tables within database B that the organization's users are sending data to.
I would like to be able to have a set-based query that can output a list of only those tables within CoreTables that are populated with data.
Dynamically, I normally would do something like:
For each row in CoreTables
Get the table name
If table is empty
Do nothing
Else
Print table name
Is there a way to do this without a cursor or other dynamic methods? Thanks for any assistance...
Probably the most efficient option is:
SELECT c.name
FROM dbo.CoreTables AS c
WHERE EXISTS
(
SELECT 1
FROM sys.partitions
WHERE index_id IN (0,1)
AND rows > 0
AND [object_id] = OBJECT_ID(c.name)
);
Just note that the count in sys.sysindexes, sys.partitions and sys.dm_db_partition_stats are not guaranteed to be completely in sync due to in-flight transactions.
While you could just run this query in the context of the database, you could do this for a different database as follows (again assuming that CoreTables does not include schema in the name):
SELECT c.name
FROM DatabaseA.CoreTables AS c
WHERE EXISTS
(
SELECT 1
FROM DatabaseB.sys.partitions AS p
INNER JOIN DatabaseB.sys.tables AS t
ON p.[object_id] = t.object_id
WHERE t.name = c.name
AND p.rows > 0
);
If you need to do this for multiple databases that all contain the same schema (or at least overlapping schema that you're capturing in aggregate in a central CoreTables table), you might want to construct a view, such as:
CREATE VIEW dbo.CoreTableCounts
AS
SELECT db = 'DatabaseB', t.name, MAX(p.rows)
FROM DatabaseB.sys.partitions AS p
INNER JOIN DatabaseB.sys.tables AS t
ON p.[object_id] = t.[object_id]
INNER JOIN DatabaseA.dbo.CoreTables AS ct
ON t.name = ct.name
WHERE p.index_id IN (0,1)
GROUP BY t.name
UNION ALL
SELECT db = 'DatabaseC', t.name, rows = MAX(p.rows)
FROM DatabaseC.sys.partitions AS p
INNER JOIN DatabaseC.sys.tables AS t
ON p.[object_id] = t.[object_id]
INNER JOIN DatabaseA.dbo.CoreTables AS ct
ON t.name = ct.name
WHERE p.index_id IN (0,1)
GROUP BY t.name
-- ...
GO
Now your query isn't going to be quite as efficient, but doesn't need to hard-code database names as object prefixes, instead it can be:
SELECT name
FROM dbo.CoreTableCounts
WHERE db = 'DatabaseB'
AND rows > 0;
If that is painful to execute you could create a view for each database instead.
In SQL Server, you can do something like:
SELECT o.name, st.row_count
FROM sys.dm_db_partition_stats st join
sys.objects o
on st.object_id = o.object_id
WHERE index_id < 2 and st.row_count > 0
By the way, this specifically does not use OBJECT_ID() or OBJECT_NAME() because these are evaluated in the current database. The above code continues to work for another database, using 3-part naming. This version also takes into account multiple partitions:
SELECT o.name, sum(st.row_count)
FROM <dbname>.sys.dm_db_partition_stats st join
<dbname>.sys.objects o
on st.object_id = o.object_id
WHERE index_id < 2
group by o.name
having sum(st.row_count) > 0
something like this?
//
foreach (System.Data.DataTable dt in yourDataSet.Tables)
{
if (dt.Rows.Count != 0) { PrintYourTableName(dt.TableName); }
}
//
This is a way you can do it, that relies on system tables, so be AWARE it may not always work in future versions of SQL. With that strong caveat in mind.
select distinct OBJECT_NAME(id) as tabName,rowcnt
from sys.sysindexes si
join sys.objects so on si.id=si.id
where indid=1 and so.type='U'
You would add to the where clause the tables you are interested in and rowcnt <1