I noticed that some date columns in a database table are giving my Power App a hard time ( patching) when the default value is '0001-01-01' and the no valid date is supplied. Note I can't just set default values in my Power App as the SQL Table is used by other applications.
My current thinking is I change the default value say to '1001-01-01' using TSQL so that I can automate it as much as possible.
Get the (DF_TABLENAME_XXXX) constraint name for the column and say shove it into a variable #mytablename
Drop this constraint name
Recreate the constraint with
ALTER TABLE #MyTable DEFAULT '1001-12-31' FOR #ColumnName
I am struggling with step 1) atm . Also I am happy to adopt a better approach than the one I have outlined.
I wrote this code sometime ago to create a Data Dictionary of sorts. It uses all the sys tables to grab information about the tables in your database. Just change the top line and you should be all set.
USE [INSERT YOUR DATABASE NAME HERE]
GO
SELECT
DB_NAME() AS [DatabaseName]
, OBJECT_SCHEMA_NAME(TBL.[object_id],DB_ID()) AS [Schema]
, TBL.[name] AS [TableName]
, AC.[name] AS [ColumnName]
, UPPER(TY.[name]) AS [DataType]
, AC.[max_length] AS [Length]
, AC.[precision] AS [Precision]
, AC.[scale] AS [Scale]
, AC.[is_nullable] AS [IsNullable]
, ISNULL(SI.is_primary_key,0) AS [IsPrimaryKey]
, SKC.name AS [PrimaryKeyConstarint]
, CASE
WHEN SIC.index_column_id > 0
THEN 1
ELSE 0
END AS [IsIndexed]
, ISNULL(is_included_column, 0) AS [IsIncludedIndex]
, SI.name AS [IndexName]
, OBJECT_NAME(SFC.constraint_object_id) AS [ForeignKeyConstraint]
, OBJECT_SCHEMA_NAME(TBL_PRIM.[object_id],DB_ID()) AS [ParentTableSchema]
, OBJECT_NAME(SFC.referenced_object_id) AS [ParentTableName]
, COL_PRIM.name AS [ParentTableColumnName]
, OBJECT_SCHEMA_NAME(TBL.[object_id],DB_ID()) + '.' + TBL.[name] + '.' + AC.[name]
+ ' = ' + OBJECT_SCHEMA_NAME(TBL_PRIM.[object_id],DB_ID()) + '.'
+ OBJECT_NAME(SFC.referenced_object_id) + '.' + COL_PRIM.name AS [JoinCondition]
, SDC.name AS [DefaultConstraint]
, SDC.[definition] AS [DefaultValue]
, AC.collation_name AS [Collation]
, SEP.value AS [Comments]
FROM [sys].[tables] AS TBL
JOIN [sys].[all_columns] AS AC
ON TBL.[object_id] = AC.[object_id]
JOIN [sys].[types] AS TY
ON AC.[system_type_id] = TY.[system_type_id]
AND AC.[user_type_id] = TY.[user_type_id]
LEFT JOIN [sys].[index_columns] AS SIC
ON sic.[object_id] = TBL.[object_id]
AND AC.column_id = SIC.column_id
LEFT JOIN [sys].[indexes] AS SI
ON SI.[object_id] = TBL.[object_id]
AND SIC.index_id = SI.index_id
LEFT JOIN [sys].[foreign_key_columns] AS SFC
ON SFC.parent_object_id = TBL.[object_id]
AND SFC.parent_column_id = AC.column_id
LEFT JOIN [sys].[key_constraints] AS SKC
ON skc.parent_object_id = TBL.[object_id]
AND SIC.index_column_id = SKC.unique_index_id
LEFT JOIN [sys].[default_constraints] AS SDC
ON SDC.parent_column_id = AC.column_id
LEFT JOIN [sys].[extended_properties] AS SEP
ON SEP.major_id = TBL.[object_id]
AND SEP.minor_id = AC.column_id
LEFT JOIN [sys].[tables] AS TBL_PRIM
ON SFC.referenced_object_id = TBL_PRIM.[object_id]
LEFT JOIN [sys].[columns] AS COL_PRIM
ON SFC.referenced_object_id = COL_PRIM.[object_id]
AND SFC.referenced_column_id = COL_PRIM.column_id
Fill in the question marks in the where clause, and this will give you the name of your default constraint.
SELECT
SchemaName = SCH.[name]
,TableName = TAB.[name]
,ColumnName = COL.[name]
,DefaultConstraint = DFC.[name]
FROM sys.default_constraints AS DFC
JOIN sys.columns AS COL
ON DFC.parent_object_id = COL.[object_id]
AND DFC.parent_column_id = COL.column_id
JOIN sys.tables AS TAB
ON COL.[object_id] = TAB.[object_id]
JOIN SYS.schemas AS SCH
ON TAB.[schema_id] = SCH.[schema_id]
WHERE SCH.[name] = ?
AND TAB.[name] = ?
AND COL.[name] = ?
Related
I have two tables TABLE1 and TABLE2.
I need to update TABLE1 with the matching primary keys from TABLE2.
Here is my code to get the primary key from TABLE1:
SELECT C.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS T
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE C ON C.CONSTRAINT_NAME = T.CONSTRAINT_NAME
WHERE C.TABLE_NAME = 'TABLE1'
AND T.CONSTRAINT_TYPE = 'PRIMARY KEY'
This is the code to get primary key for TABLE2:
SELECT C.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS T
JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE C ON C.CONSTRAINT_NAME = T.CONSTRAINT_NAME
WHERE C.TABLE_NAME = 'TABLE2'
AND T.CONSTRAINT_TYPE = 'PRIMARY KEY'
And this code is used to update TABLE1:
MERGE INTO <TABLE1>
USING <TABLE2> ON (TABLE1.COLUMN_NAME = TABLE2.COLUMN_NAME)
WHEN MATCHED THEN
UPDATE
SET <TABLE1.COLUMN_NAME> = <TABLE1.COLUMN_NAME>
I need to merge all snippets of code to update the TABLE1, please help me how to get the primary keys and update with a single code.
As #GuidoG recommended, you will probably need to use dynamic SQL to perform this feat. Furthermore, from your question it is hard to figure out how to determine that Table1 and Table2 are related to one another.
Let us suppose that you have a table with table pairs available, and Table1 and Table 2 are one of those pairs. We'll need to figure out what the primary keys of both tables are, and then build the dynamic SQL using this information.
DECLARE #tableCombinations TABLE ([MainTable] NVARCHAR(255), [SubTable] NVARCHAR(255))
INSERT INTO #tableCombinations ([MainTable], [SubTable]) VALUES ('Table1','Table2')
DECLARE #q NVARCHAR(MAX) = ''
;WITH PrimaryKeys AS (
SELECT [Schema_Name] = sch.[name]
, [Table_Name] = tbl.[name]
, [Column_Name] = cols.[name]
FROM [sys].[indexes] i
JOIN [sys].[index_columns] ic ON i.[index_id] = ic.[index_id] AND i.[object_id] = ic.[object_id]
JOIN [sys].[columns] cols ON cols.[object_id] = ic.[object_id] AND cols.[column_id] = ic.[column_id]
JOIN [sys].[tables] tbl ON ic.[object_id] = tbl.[object_id]
JOIN [sys].[schemas] sch ON tbl.[schema_Id] = sch.[schema_id]
WHERE i.[is_primary_key] = 1
)
SELECT #q += 'MERGE INTO ' + QUOTENAME(pkMain.[Schema_Name]) + '.' + QUOTENAME(pkMain.[Table_Name]) +' mt
USING ' + QUOTENAME(pkSub.[Schema_Name]) + '.' + QUOTENAME(pkSub.[Table_Name]) + 'st ON (
mt.' + QUOTENAME(pkMain.[Column_Name]) + ' = st.' + pkSub.[Column_Name] + ')
WHEN MATCHED THEN UPDATE SET mt.' + QUOTENAME(pkMain.[Column_Name]) + ' = st.' + pkSub.[Column_Name] + ';' + CHAR(13) + CHAR(10)
FROM #tableCombinations tc
JOIN [PrimaryKeys] pkMain ON tc.[MainTable] = pkMain.[Table_Name]
JOIN [PrimaryKeys] pkSub ON tc.[SubTable] = pkSub.[Table_Name]
SET #q = REPLACE(#q, ' ', '')
SELECT #q
Of course, if this yields the correct results, you can directly execute this query using [sys].[sp_executesql]. For more reliable results, be sure to include the schema names of the table combinations.
I've been tasked with moving all tables in a single snapshot replication that have primary keys to the transaction replication. We get vendor updates and they may have added keys to tables that were in the Snapshot replication.
I've tried to break it down into 2 steps, finding all tables in a snapshot replication, and then checking to see if those tables have a primary key.
I've tried to piece together a few different code samples, but I may need to start over, here's what I've got so far.
--=============================================================================================
SELECT DB_NAME () PublisherDB
, sp.name AS PublisherName
, sa.name AS TableName
, UPPER (srv.srvname) AS SubscriberServerName
,*
FROM dbo.syspublications sp
JOIN dbo.sysarticles sa ON sp.pubid = sa.pubid
JOIN dbo.syssubscriptions s ON sa.artid = s.artid
JOIN master.dbo.sysservers srv ON s.srvid = srv.srvid;
--=============================================================================================
SELECT DB_NAME () AS db
, SCHEMA_NAME (o.schema_id) AS [Schema]
, so.name AS table_name
, so.type
, CASE WHEN TABLE_NAME IN (
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY'
) THEN 1 ELSE 0 END AS HasPrimaryKey
--INTO #t2
FROM sys.objects o WITH (NOLOCK)
INNER JOIN sysobjects so WITH (NOLOCK)
--INNER JOIN #t1 ON t1.
LEFT OUTER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t2 ON t2.TABLE_NAME = so.name ON so.id = o.object_id
WHERE (
(so.xtype = 'U') -- user table xtype: learn.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysobjects-transact-sql?view=sql-server-ver15
OR (so.xtype = 'V') -- view
OR (so.xtype = 'P') -- stored procedure
)
AND so.category <> 2
AND so.name IN (
SELECT DISTINCT OBJECT_NAME (objid) FROM dbo.sysarticles
)
ORDER BY so.name
, so.type;
--=============================================================================================
DECLARE #jobId UNIQUEIDENTIFIER;
DECLARE #jobName sysname;
SELECT #jobId = jobs.job_id
, #jobName = jobs.name
FROM msdb.dbo.sysjobs jobs (NOLOCK)
JOIN msdb.dbo.syscategories categories (NOLOCK) ON jobs.category_id = categories.category_id
WHERE categories.name = 'REPL-Snapshot'
AND jobs.name LIKE '%db-name%';
SELECT #jobId
, #jobName;
EXEC sp_start_job #job_id = #jobId;
This is what I ended up going with. I pieced together and tweaked various snippets of code I've found.
Some from here: https://dataedo.com/kb/query/sql-server/list-tables-with-their-primary-keys
Other code from here: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/50c6890b-8dc1-46c6-aeda-d97149a9692f/list-all-replicated-tables-and-their-destination?forum=sqlreplication
--====================================================================================================================================================
-- Get tables in Snapshot replication for the selected DB.
--====================================================================================================================================================
IF OBJECT_ID ('tempdb..#t1') IS NOT NULL DROP TABLE #t1;
SELECT pub.name AS [Publication]
, CASE WHEN pub.name LIKE '%Snapshot%' THEN 'SnapShot'
WHEN pub.name LIKE '%Transaction%' THEN 'Transaction' ELSE NULL END AS ReplicationType
, art.name AS [Article]
, serv.name AS [Subsriber]
, sub.dest_db AS [DestinationDB]
, obj.object_id
, CASE WHEN obj.type = 'U' THEN 'Table'
WHEN obj.type = 'V' THEN 'View'
WHEN obj.type = 'P' THEN 'SP' ELSE NULL END AS ObjectType
INTO #t1
FROM dbo.syssubscriptions sub
INNER JOIN sys.servers serv ON serv.server_id = sub.srvid
INNER JOIN dbo.sysarticles art ON art.artid = sub.artid
INNER JOIN dbo.syspublications pub ON pub.pubid = art.pubid
INNER JOIN sys.objects obj ON obj.object_id = art.objid
WHERE CASE WHEN pub.name LIKE '%Snapshot%' THEN 'SnapShot'
WHEN pub.name LIKE '%Transaction%' THEN 'Transaction' ELSE NULL END = 'Snapshot';
--====================================================================================================================================================
-- Check for primary keys on the above tables
--====================================================================================================================================================
SELECT SCHEMA_NAME (tab.schema_id) AS [schema_name]
, tab.[name] AS table_name
, pk.[name] AS pk_name
, SUBSTRING (column_names, 1, LEN (column_names) - 1) AS [columns]
FROM sys.tables tab
LEFT OUTER JOIN sys.indexes pk ON tab.object_id = pk.object_id
AND pk.is_primary_key = 1
CROSS APPLY (
SELECT col.[name] + ', '
FROM sys.index_columns ic
INNER JOIN sys.columns col ON ic.object_id = col.object_id
AND ic.column_id = col.column_id
WHERE ic.object_id = tab.object_id
AND ic.index_id = pk.index_id
ORDER BY col.column_id
FOR XML PATH ('')
) D(column_names)
WHERE pk.object_id IN (
SELECT object_id FROM #t1
)
ORDER BY SCHEMA_NAME (tab.schema_id)
, tab.[name];
My requirement is to Join table A and table D. I know there are tables B and C in between which have PK and FK relationships. I want a query to know the tables B and C and the keys involved in the relationship. I need to know this for the entire database. Database diagram will give me the relationship but I don't have permissions to view the diagram. Moreover, I need to look for each set of tables. That's why I am trying to write a query that does the job for me.
In short, if I provide Table A and Table D to the query then query should give me essential columns required (in our case B.id2,C.id3) to join A and D.
SELECT A.*, D.* FROM A Join B on A.id1 = B.id2 Join C on B.id2 = C.id3 Join D on C.id3 = D.id4
Thanks in advance.
I pulled up the one I wrote at work; looks like I didn't actually bother with the CTE (since they're a royal pain in the butt IMHO). It's a little lengthy since it's just code I ripped from a proc. My version originally didn't include the columns, but I added them in. I just concatenate them as though they were an ON clause, but you can tweak that how you like.
use AdventureWorks2014
go
declare
#BaseTable nvarchar(128) = 'SalesPerson',
#BaseTableSchema nvarchar(128) = 'Sales'
declare
#Depth int = 0,
#RowCount int,
#Ident int
declare #KeyHierarchy table
(
Depth int,
ReferencingTableSchema nvarchar(128),
ReferencingTableName nvarchar(128),
ReferencingObjectId int,
ReferencingTableNameFull as quotename(ReferencingTableSchema) + '.' + quotename(ReferencingTableName),
ReferencedTableSchema nvarchar(128),
ReferencedTableName nvarchar(128),
ReferencedObjectId int,
ReferencedTableNameFull as quotename(ReferencedTableSchema) + '.' + quotename(ReferencedTableName),
MatchingColumns nvarchar(max)
primary key clustered (ReferencingTableSchema, ReferencingTableName)
)
insert into #KeyHierarchy
(
Depth,
ReferencingTableSchema,
ReferencingTableName,
ReferencingObjectId
)
select
Depth = #Depth,
ReferencingTableSchema = #BaseTableSchema,
ReferencingTableName = #BaseTable,
ReferencingObjectId = object_id(#BaseTableSchema + '.' + #BaseTable)
select #RowCount = 1
while #RowCount > 0
begin
insert into #KeyHierarchy
(
Depth,
ReferencedTableSchema,
ReferencedTableName,
ReferencedObjectId,
ReferencingTableSchema,
ReferencingTableName,
ReferencingObjectId,
MatchingColumns
)
select distinct
Depth = #Depth + 1,
ReferencedTableSchema = object_schema_name(f.referenced_object_id),
ReferencedTableName = object_name(f.referenced_object_id),
ReferencedObjectId = f.referenced_object_id,
ReferencingTableSchema = object_schema_name(f.parent_object_id),
ReferencingTableName = object_name(f.parent_object_id),
ReferencingObjectId = f.parent_object_id,
MatchingColumns = stuff
(
(
select
concat
(
' and parent.',
quotename(col_name(c.parent_object_id, c.parent_column_id)),
' = ',
'referenced.',
quotename(col_name(c.referenced_object_id, c.referenced_column_id))
)
from sys.foreign_key_columns c
where f.object_id = c.constraint_object_id
order by c.constraint_column_id
for xml path(''), type
).value('.', 'nvarchar(max)'), 1, 4, ''
)
from #KeyHierarchy k
inner join sys.foreign_keys f
on f.referenced_object_id = k.ReferencingObjectId
and f.parent_object_id not in (select ReferencingObjectId from #KeyHierarchy where Depth < #Depth + 1)
where k.Depth = #Depth
select
#RowCount = ##RowCount,
#Depth += 1
end
select
BaseTable = #BaseTable,
ReferencingTableNameFull,
ReferencedTableNameFull,
MatchingColumns,
Depth
from #KeyHierarchy
order by Depth, ReferencingTableNameFull
This has some problems but it is a start
select t.name [t_name], c.name [c_name], f.*
from sys.foreign_keys f
join sys.tables t
on f.parent_object_id = t.object_id
and f.type = 'F'
left join sys.columns c
on c.object_id = f.referenced_object_id
and c.system_type_id = 56
You can fiddle about from this starting point:
with
ForeignKeys as (
-- All foreign keys with their associated tables and columns.
select fk.name as ConstraintName, fk.object_id as ContraintObjectId,
pt.name as ParentTable, pt.object_id as ParentTableObjectId, pc.name as ParentColumn, pc.column_id as ParentColumnId,
ft.name as ForeignTable, ft.object_id as ForeignTableObjectId, fc.name as ForeignColumn, fc.column_id as ForeignColumnId
from sys.foreign_keys as fk inner join
sys.foreign_key_columns as fkc on fkc.constraint_object_id = fk.object_id inner join
sys.tables as pt on pt.object_id = fkc.parent_object_id inner join
sys.columns as pc on pc.object_id = pt.object_id and pc.column_id = fkc.parent_column_id inner join
sys.tables as ft on ft.object_id = fkc.referenced_object_id inner join
sys.columns as fc on fc.object_id = ft.object_id and fc.column_id = fkc.referenced_column_id ),
RelatedTables as (
-- All ordered pairs of directly related tables.
select distinct ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId
from ForeignKeys ),
RelatedTablesHierarchy as (
-- Hierarchy of related tables.
-- Start from each distinct table that has a foreign key relation ...
select ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId,
Cast( ParentTable + '»' + ForeignTable as NVarChar(4000) ) as Path
from RelatedTables
union all
-- ... and add any other table to which the foreign table is related.
select RTH.ParentTable, RTH.ParentTableObjectId, RT.ForeignTable, RT.ForeignTableObjectId,
Cast( Path + '»' + RT.ForeignTable as NVarChar(4000) )
from RelatedTablesHierarchy as RTH inner join
RelatedTables as RT on RT.ParentTableObjectId = RTH.ForeignTableObjectId
-- NB: Avoid getting caught in reference loops.
where '»' + Path + '»' not like '%»' + RT.ForeignTable + '»%'
)
-- Output the results with Path made a little easier to read.
select Replace( Path, '»', ' » ' ) as Path, ParentTable, ParentTableObjectId, ForeignTable, ForeignTableObjectId
from RelatedTablesHierarchy
order by Path;
The initial query is certainly carrying some extra baggage, but you will need it to determine the table and column names necessary for joins. (Tip: Use QuoteName() when assembling object names into statements.)
NB: The common table expression is resistant to reference loops, e.g. tables that have foreign key references to themselves as well as longer loops involving multiple tables.
I am attempting to insert data about index usage into a control database of sorts.. The query I am using is below.. the issue I have is that when I execute the query from the control database (lets call it A) it returns 0 results, but if I execute it from the source database (lets call that B) it runs just fine..
why?
This behavior is being seen on both SQL Server 2012 DEV and SQL Server 2008 EE.
Example 1 returns zero results:
USE A;
INSERT INTO A.dbo.UnusedIndexes
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(o.object_id) AS TableName
, ix.name AS IndexName
,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
, ix_usage_stats.user_updates
, ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
AS [User_SeeksScansLookups]
, ix_usage_stats.system_updates
, ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
AS [System_SeeksScansLookups]
, NULL as [Drop_Statement]
, NULL as [Create_statement]
,getdate() as [date_added]
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE
ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting')
AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)
Example 2 returns the expected results, populating A.dbo.UnusedIndexes:
USE B;
INSERT INTO A.dbo.UnusedIndexes
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(o.object_id) AS TableName
, ix.name AS IndexName
,((SUM(ps.used_page_count)over(partition by ix.index_id))*8)/1024 AS [IndexSizeMB]
, ix_usage_stats.user_updates
, ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups
AS [User_SeeksScansLookups]
, ix_usage_stats.system_updates
, ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups
AS [System_SeeksScansLookups]
, NULL as [Drop_Statement]
, NULL as [Create_statement]
,getdate() as [date_added]
FROM B.sys.indexes ix
Left join B.sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN B.sys.objects o ON ix.object_id = o.object_id
JOIN B.sys.dm_db_partition_stats ps ON ps.object_id = ix.object_id AND ix.index_id = ps.index_id
WHERE
ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN('F', 'UQ') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in ('dbo','stats', 'reporting')
AND (ix_usage_stats.user_seeks = 0 or ix_usage_stats.user_seeks is NULL)
AND (ix_usage_stats.user_scans = 0 or ix_usage_stats.user_scans is null)
AND (ix_usage_stats.user_lookups = 0 or ix_usage_stats.user_lookups is null)
This works all day long:
USE A;
Select * from B.sys.indexes
Any help would be great - and unfortunately I am unable to execute this from database B, so the easy solution won't work.
Solved
Figured it out. the DB_NAME() was the issue. removing that and setting it to 'B' as databasename fixed the issue.
Try using sp_executesql from the target database:
USE A;
INSERT INTO A.dbo.UnusedIndexes
EXEC B.sys.sp_executesql N'
SELECT DB_NAME() AS DatabaseName
,SCHEMA_NAME(o.Schema_ID) AS SchemaName
,OBJECT_NAME(o.object_id) AS TableName
,ix.NAME AS IndexName
,((SUM(ps.used_page_count) OVER (PARTITION BY ix.index_id)) * 8) / 1024 AS [IndexSizeMB]
,ix_usage_stats.user_updates
,ix_usage_stats.user_seeks + ix_usage_stats.user_scans + ix_usage_stats.user_lookups AS [User_SeeksScansLookups]
,ix_usage_stats.system_updates
,ix_usage_stats.system_seeks + ix_usage_stats.system_scans + ix_usage_stats.system_lookups AS [System_SeeksScansLookups]
,NULL AS [Drop_Statement]
,NULL AS [Create_statement]
,getdate() AS [date_added]
FROM sys.indexes ix
LEFT JOIN sys.dm_db_index_usage_stats ix_usage_stats
ON ix_usage_stats.object_id = ix.object_id
AND ix_usage_stats.index_id = ix.index_id
INNER JOIN sys.objects o
ON ix.object_id = o.object_id
JOIN sys.dm_db_partition_stats ps
ON ps.object_id = ix.object_id
AND ix.index_id = ps.index_id
WHERE 1 = 1
AND ix.name IS NOT NULL -- exclude heaps
AND ix.type <> 1 -- exclude the clustered indexes
AND o.is_ms_shipped = 0 -- exclude system objects
AND o.type NOT IN(''F'', ''UQ'') -- exclude the foreign keys and unique contraints
AND SCHEMA_NAME(o.schema_id) not in (''dbo'',''stats'', ''reporting'')
AND (
ix_usage_stats.user_seeks = 0
OR ix_usage_stats.user_seeks IS NULL
)
AND (
ix_usage_stats.user_scans = 0
OR ix_usage_stats.user_scans IS NULL
)
AND (
ix_usage_stats.user_lookups = 0
OR ix_usage_stats.user_lookups IS NULL
)
'
I'm trying to amend the following script to point at just the indexes associated with a particular view vw_foo. Is this possible?
SELECT name AS index_name,
STATS_DATE(OBJECT_ID, index_id) AS StatsUpdated
FROM sys.indexes
Edit
When I say "associated" I mean the indexes on the underlying tables that are used to create the view
Possibly, it will be helpful for you -
SELECT
SCHEMA_NAME(o.[schema_id]) + '.' + o.name
, s.name
, statistics_update_date = STATS_DATE(o.[object_id], stats_id)
FROM sys.objects o
JOIN sys.stats s ON o.[object_id] = s.[object_id]
WHERE o.[type] = 'V' AND o.name = 'vw_foo'
DECLARE #table_name SYSNAME
SELECT #table_name = 'dbo.vw_foo'
EDITED
When I say "associated" I mean the indexes on the tables that are used
by the view
This query returns the list of the views where is used the specified table + shows additional info about the used index -
SELECT
o.table_name
, b.view_name
, i.name
, stast_updates = STATS_DATE(i.[object_id], i.index_id)
, dm_ius.last_user_seek
, dm_ius.last_user_scan
, dm_ius.last_user_lookup
, dm_ius.last_user_update
, dm_ius.user_updates
, dm_ius.user_lookups
, dm_ius.user_scans
, dm_ius.user_seeks
FROM (
SELECT
table_name = s.name + '.' + o.name
, o.[object_id]
FROM sys.objects o
JOIN sys.schemas s ON o.[schema_id] = s.[schema_id]
WHERE o.[type] = 'U'
AND s.name + '.' + o.name = #table_name
) o
JOIN sys.indexes i ON o.[object_id] = i.[object_id]
AND i.[type] > 0
AND i.is_disabled = 0
AND i.is_hypothetical = 0
LEFT JOIN sys.dm_db_index_usage_stats dm_ius ON i.index_id = dm_ius.index_id AND dm_ius.[object_id] = i.[object_id]
OUTER APPLY (
SELECT
view_name = r.referencing_schema_name + '.' + r.referencing_entity_name
, r.referencing_id
FROM sys.dm_sql_referencing_entities (o.table_name, 'OBJECT') r
JOIN sys.objects o2 ON r.referencing_id = o2.[object_id]
WHERE o2.[type] = 'V'
) b
WHERE b.view_name IS NOT NULL
The existing answers were probably heading towards checking the name in sys.objects but never do it. But there's no need to do so anyway, since the OBJECT_ID() function lets you get an object_id in a clean fashion:
SELECT name AS index_name,
STATS_DATE(OBJECT_ID, index_id) AS StatsUpdated
FROM sys.indexes
WHERE object_id = OBJECT_ID('vw_foo')