I have a file group within a database that has no logical files that cannot be removed. The error message states that the file group is not empty.
I have verified that no partitions exist using the queries below.
SELECT * FROM sys.partition_functions
SELECT * FROM SYS.PARTITION_RANGE_VALUES
SELECT * FROM SYS.PARTITION_SCHEMES
I have also run the queries below in a effort to find anything associated with the file group, but found nothing
SELECT
au.*,
ds.name AS [data_space_name],
ds.type AS [data_space_type],
p.rows,
o.name AS [object_name]
FROM sys.allocation_units au
INNER JOIN sys.data_spaces ds
ON au.data_space_id = ds.data_space_id
INNER JOIN sys.partitions p
ON au.container_id = p.partition_id
INNER JOIN sys.objects o
ON p.object_id = o.object_id
ORDER BY ds.name;
SELECT *
FROM sys.filegroups fg
LEFT OUTER JOIN sysfilegroups sfg
ON fg.name = sfg.groupname
LEFT OUTER JOIN sysfiles f
ON sfg.groupid = f.groupid
LEFT OUTER JOIN sys.allocation_units i
ON fg.data_space_id = i.data_space_id
WHERE i.data_space_id IS NULL;
select * from sys.allocation_units
where data_space_id = (select data_space_id from sys.data_spaces where name = 'HL7');
In addition, I have been able to backup the database and restore to a different SQL Server and duplicate this problem.
What else can be checked to find out what is preventing the file group from being removed?
I had a similar situation recently. I ran
DBCC SHRINKFILE (N'myfile', EMPTYFILE)
after which I was able to remove the file.
Frankly I didn't expect it to work, since in my case the filegroup has no other files in it. So even though the operation should
Migrates all data from the specified file to other files in the same
filegroup
There was no file to migrate the data to. But it worked! No errors or warnings. Right after I removed the file without issue. Guessing that there was some messed up entries that bothered REMOVE FILE but not SHRINKFILE.
Give it a go and post your results here.
Related
There's a requirement where I need to get the table row count information without using count function. Currently I have used the below code to achieve it:
SELECT
CONCAT(schemas.name, '.', tables.name) as tableName,
partitions.rows AS tableRowCount
FROM
sys.partitions
JOIN
sys.tables ON tables.object_id = partitions.object_id
JOIN
sys.schemas ON tables.schema_id = schemas.schema_id
But for some reason, this query is not working properly as expected. Having said that, in some cases tableRowCount is different if the same is checked using the count function.
Is there a way to overcome this challenge?
Please note I tried using sys.dm_db_partition_stats table as well.
However, I get this error:
Msg 104385, Level 16, State 1, Line 9
Catalog view 'dm_db_partition_stats' is not supported in this version.
Please help.
This should be much faster than using COUNT.
SELECT SUM(p.rows) FROM sys.partitions AS p
INNER JOIN sys.tables AS t ON p.[object_id] = t.[object_id]
INNER JOIN sys.schemas AS s ON s.[schema_id] = t.[schema_id]
WHERE t.name = N'(yourtable)' AND s.name = N'dbo' AND p.index_id IN (0,1);
Note that this approach is in no way portable between RDBMSs.
I am trying to implement switch partitioning on one of the tables and I made sure that the partition function,scheme,file groups are working fine. But I get the file group error when I run the below command. Can someone share your thoughts on this.
Command :-
ALTER TABLE XYZ SWITCH PARTITION 5 TO ABC PARTITION 5;
Error :-
ALTER TABLE SWITCH statement failed. table 'XYZ' is in filegroup 'PRIMARY' and partition 5 of table 'ABC' is in filegroup 'FG_5'.
Some cluster index might be created on the existing tables . So file group is mentioned during creation of cluster index on the tables that might be different. or so if you can delete the ABC table and create again and try your query.
Query to check the filegroup of the table and index names.
select f.name,o.name,i.name from sys.indexes i inner join sys.filegroups f on i.data_space_id=f.data_space_id
inner join sys.all_objects o on o.object_id= i.object_id
where o.name in ('ABC','XYZ')
I won't say this is solution but this should help in solving the problem.
The error indicates that the source and target tables are not storage aligned. Run the query below to make sure the source and target filegroups are identical both the table and indexes:
SELECT
OBJECT_NAME(p.object_id) AS ObjectName,
i.name AS IndexName,
p.index_id AS IndexID,
ds.name AS PartitionScheme,
p.partition_number AS PartitionNumber,
fg.name AS FileGroupName,
prv_left.value AS LowerBoundaryValue,
prv_right.value AS UpperBoundaryValue,
CASE pf.boundary_value_on_right WHEN 1 THEN 'RIGHT' ELSE 'LEFT' END AS PartitionFunctionRange,
p.rows AS Rows
FROM
sys.partitions AS p INNER JOIN
sys.indexes AS i ON i.object_id = p.object_id AND i.index_id = p.index_id INNER JOIN
sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id INNER JOIN
sys.partition_schemes AS ps ON ps.data_space_id = ds.data_space_id INNER JOIN
sys.partition_functions AS pf ON pf.function_id = ps.function_id INNER JOIN
sys.destination_data_spaces AS dds2 ON dds2.partition_scheme_id = ps.data_space_id AND dds2.destination_id = p.partition_number INNER JOIN
sys.filegroups AS fg ON fg.data_space_id = dds2.data_space_id LEFT OUTER JOIN
sys.partition_range_values AS prv_left ON ps.function_id = prv_left.function_id AND prv_left.boundary_id = p.partition_number - 1 LEFT OUTER JOIN
sys.partition_range_values AS prv_right ON ps.function_id = prv_right.function_id AND prv_right.boundary_id = p.partition_number
WHERE
p.object_id IN (
OBJECT_ID(N'dbo.ABC')
, OBJECT_ID(N'dbo.XYZ')
)
AND p.partition_number = 5
ORDER BY
ObjectName
,IndexName
,PartitionNumber;
Check your partitionscheme. Both tables should be in the same filegroup. You should involve PRIMARY in you partition scheme or move the SOURCE table to the destination FILEGROUPS that the destination table will be using.
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
To discover all triggers in any given MS SQL Server database, I'm currently querying the sysobjects table (which is fine because it works in MS SQL Server 2000 which I have to support) e.g.
SELECT R1.name AS trigger_name,
T1.name AS trigger_parent_table_name
FROM sysobjects AS R1
INNER join sysobjects AS T1
ON R1.parent_obj = T1.id
WHERE R1.xtype = 'tr';
This gives me a reduced list of trigger names and for each I can use
EXEC sp_helptext 'trigger_name_here'
to find the definition. That works fine for databases where only the default dbo schema is used.
I now have a MS SQL Server 2005 database which uses multiple schemas. What is the best way of discovering the schema for each trigger?
You are looking for the parent object for a trigger so it will always be a table. In sys.tables (system view) you get the schema_id and with it you can go sys.schemas (system view too) to get the schema's name.
Hope this helps.
--
EDIT:
The code:
SELECT sys.objects.name AS [trigger],
sys.tables.name AS [table],
sys.objects.type,
sys.schemas.name AS [schema]
FROM sys.schemas RIGHT OUTER JOIN
sys.tables ON sys.schemas.schema_id = sys.tables.schema_id RIGHT OUTER JOIN
sys.objects ON sys.tables.object_id = sys.objects.parent_object_id
WHERE sys.objects.type = 'tr'
This is is with sys.tables but you can do it with only sys.objects, this is a general select to look for parents and schemas:
SELECT O.name, O.type, S.name AS [schema],
OP.name AS parent_name, OP.type AS parent_type, SP.name AS parent_schema
FROM sys.schemas AS SP RIGHT OUTER JOIN
sys.objects AS OP ON SP.schema_id = OP.schema_id RIGHT OUTER JOIN
sys.objects AS O LEFT OUTER JOIN
sys.schemas AS S ON O.schema_id = S.schema_id ON OP.object_id = O.parent_object_id
I want to check in Transact SQL if a specific column in a table has statistics and if so to get them all.
This query should do it.
I use it in a stored proc that browse the DB to find stats.
Works in SQL Server 2005 and probably older version as well.
SELECT S.NAME
FROM SYS.OBJECTS AS O
INNER JOIN SYS.STATS AS S
ON O.OBJECT_ID = S.OBJECT_ID
INNER JOIN SYS.STATS_COLUMNS AS SC
ON SC.OBJECT_ID = S.OBJECT_ID
AND S.STATS_ID = SC.STATS_ID
WHERE (O.OBJECT_ID = OBJECT_ID('MyTable','local'))
AND (O.TYPE IN ('U'))
AND (INDEXPROPERTY(S.OBJECT_ID,S.NAME,'IsStatistics') = 1) /* only stats */
AND (COL_NAME(SC.OBJECT_ID,SC.COLUMN_ID) = 'MyColumn')