I have a query that successfully lists a databases table hierarchy in relation to level of FK/checks on referenced tables and columns.
This will depict the order in which data is deleted/inserted.
Problem is, within this I want to include that path i.e.
levels 1 through to 'x' but also the group path each follows (some might have multiple paths through the levels).
Anyone have any suggestions, currently use CTE to recursively grab the level. Possibly use the FK referenced table-name?
;with cteTbHierarchy
as (
SELECT distinct
1 as LevelID
, OBJECT_SCHEMA_NAME(Parent.object_id) as TableOwner
, Parent.name as TableName
, Parent.object_id as TbObjID
, OBJECT_NAME(RefKey.referenced_object_id) as Referenced_Tablename
, RefKey.referenced_object_id
, RefKey.referenced_column_id
from sys.objects Parent
left outer join sys.foreign_key_columns RefKey
On RefKey.parent_object_id = Parent.object_id
and RefKey.parent_object_id <> RefKey.referenced_object_id
and RefKey.constraint_column_id = 1
where RefKey.parent_object_id is null
and Parent.type = 'U'
and Parent.name <> 'dtproperties'
UNION ALL
/* add tables that reference the anchor rows */
SELECT H.LevelID + 1
, OBJECT_SCHEMA_NAME(Parent.object_id) as TableOwner
, OBJECT_NAME(Parent.object_id) as TableName
, Parent.object_id as TbObjID
, OBJECT_NAME(RefKey.referenced_object_id) as Referenced_Tablename
, RefKey.referenced_object_id
, RefKey.referenced_column_id
from sys.objects Parent
inner join sys.foreign_key_columns RefKey
On RefKey.parent_object_id = Parent.object_id
and RefKey.parent_object_id <> RefKey.referenced_object_id
and RefKey.constraint_column_id = 1
inner join cteTbHierarchy H
on H.TbObjID = RefKey.referenced_object_id
where Parent.type = 'U'
and Parent.name <> 'dtproperties'
)
select distinct a.LevelID,
a.TableOwner,
a.TableName,
a.Referenced_Tablename,
cols.name as Referenced_ColName,
REPLACE(a.tablename,(LEFT(SUBSTRING(a.TableName, charindex('.',a.TableName), 50),50)),'') as TableArea,
REPLACE(a.Referenced_Tablename,(LEFT(SUBSTRING(a.Referenced_Tablename, charindex('.',a.Referenced_Tablename), 50),50)),'') as RefTableArea
from cteTbHierarchy a
left join sys.columns cols
on a.referenced_object_id = cols.object_id
AND a.referenced_column_id = cols.column_id
order by LevelID asc
, TableName;
Related
I have a view which queries around 1+ million rows and takes around 10-15 minutes to finish its execution,I want to provide cluster indexing to it so that it exists in physical schema and takes less time to load, but there are a number of constraints in order to provide cluster indexing i.e. only INNER JOIN are allowed and No subqueries should be present in views defination how do I replace the LEFT JOIN present in this view with INNER JOIN and how do I eliminate subqueries from this views defination so that cluster indexing can be applied to it.
CREATE view [dbo].[FTM_ProfileDetailsView] with SCHEMABINDING as
select FTM.Id
, FTM.EmployeeId
, FTM.CustomerId
, FTM.AbsenceFirstDate
, FTM.BackgroundHistory
, FTM.BackgroundHistoryComments
, FTM.IsEmployeeAbsent,FTM.ServiceId
, Case When isnull(FTM.IsSelfManagement,'')='' THEN cast(0 as bit) ELSE FTM.IsSelfManagement END as IsSelfManagement
, PR.ServiceLineId,FTM.ProfileId,PR.StatusId,Status.Status as StatusName
, PR.ReasonID
, PR.ModifiedDate
, PR.WithdrawnReason
, PR.CreatedBy
, PR.CreatedDate
, PR.IsActive
, mgrs.usernames as LineManagers
, cust.CustomerName
, ltrim(rtrim( emp.EmployeeTitle+' '+ emp.FirstName+' '+ emp.Surname)) as EmployeeFullName
, FTM.ProfileManagerId
, FTM.IsProfileManagement
, AM.MonitoringChecks
, AM.Frequency
, AM.ProfileManagerNotes
, AM.TaskDateAndTime
, FTM.ProfileManagementCriteriaId
,cast(case when PR.StatusId = 13 then 1 else 0 end as bit) as IsActiveMonitoring
, CustServ.CustomerServiceName
, BU.Name as BusinessUnit
, emp.DASID
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
, (select top 1
StatusId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc) as LatestInterventionStatusId
, (select name from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc))
as LatestInterventionName from FTM_Profile FTM
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
INNER JOIN dbo.PR_Profile PR on PR.Profileid=FTM.ProfileId
LEFT JOIN dbo.BusinessUnit BU on BU.Id=PR.BUId
LEFT JOIN dbo.PR_dv_Status [Status] on [Status].Id = PR.StatusId
LEFT JOIN dbo.CM_ActiveMonitoringDetails AM on AM.ProfileId = PR.Profileid
LEFT JOIN dbo.FTM_CustomerServiceMapping CustServ on CustServ.ServiceId = FTM.ServiceId and CustServ.CustomerId = FTM.CustomerId
LEFT JOIN dbo.contact con on con.Id = emp.ContactID
LEFT JOIN dbo.address addr on addr.Id = con.HomeAddressId
LEFT JOIN dbo.contactinfo coninfo on coninfo.Id = con.ContactInfoId
I have a suggestion. Can you try and change your query so the sub -queries in the SELECT are placed in CROSS APPLYs?
So something along the lines of this in your WHERE clause:
CROSS APPLY (
select top 1 StatusId AS LatestInterventionStatusId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc
) LatestInterventionStatusId
CROSS APPLY (
select name AS LatestInterventionName
from dbo.FTM_Intervention Intr
where Intr.Id=(select top 1 InterventionId
from dbo.PR_Profileintervention ProfileInt
where ProfileInt.ProfileId=FTM.Profileid
order by ProfileInt.Id desc)
)LatestInterventionName
And then of course change the column names in the SELECT to something like this:
, LatestInterventionStatusId.LatestInterventionStatusId
, LatestInterventionName.LatestInterventionName
Give this a go and let me know if it makes a different.
Ok, you didn't give me an answer on my question, but the subqueries should be changed. Try to use this instead the two subqueries:
/*
...
, emp.DateOfBirth as EmployeeDOB
, addr.PostCode
, coninfo.Email
*/
, p.StatusId as LatestInterventionStatusId
, p.name as LatestInterventionName
from FTM_Profile FTM
OUTER APPLY (
select TOP 1 Intr.name, ProfileInt.StatusId
from dbo.PR_Profileintervention ProfileInt
LEFT JOIN dbo.FTM_Intervention Intr ON Intr.Id = ProfileInt.InterventionId
where ProfileInt.ProfileId = FTM.Profileid
order by ProfileInt.Id desc
) p
/*
LEFT JOIN dbo.ProfileManagersView mgrs ON mgrs.ProfileID = FTM.ProfileID
INNER JOIN dbo.Customer cust on cust.Id= FTM.CustomerId
INNER JOIN dbo.Employee emp on emp.Id = FTM.EmployeeId
...
*/
I have a requirement to get all the database tables name which are used in specific stored procedure?
As an example, I have one stored procedure as given below.
CREATE PROCEDURE [dbo].[my_sp_Name]
#ID INT = NULL
AS
BEGIN
SELECT ID, NAME, PRICE
FROM tbl1
INNER JOIN tbl2 ON tbl1.ProductId = tbl2.ProductId
LEFT JOIN tbl3 ON tbl2.ProductSalesDate = tbl3.ProductSalesDate
LEFT JOIN tbl4 ON tbl1.ProductCode = tbl4.ItemCode
END
Expected output:
Used_Table_Name
tbl1
tbl2
tbl3
tbl4
Can any one suggest a way?
Below query will help you to get used database tables in stored procedure.
;WITH stored_procedures AS (
SELECT oo.name AS table_name,
ROW_NUMBER() OVER(partition by o.name,oo.name ORDER BY o.name,oo.name) AS row
FROM sysdepends d
INNER JOIN sysobjects o ON o.id=d.id
INNER JOIN sysobjects oo ON oo.id=d.depid
WHERE o.xtype = 'P' AND o.name = 'my_sp_Name'
)
SELECT Table_name AS 'Used_Table_Name' FROM stored_procedures
WHERE row = 1
Use below script to get table names in your store procedure :
SELECT DISTINCT [object_name] = SCHEMA_NAME(o.[schema_id]) + '.' + o.name
, o.type_desc
FROM sys.dm_sql_referenced_entities ('[dbo].[Your_procedurename]',
'OBJECT')d
JOIN sys.objects o ON d.referenced_id = o.[object_id]
WHERE o.[type] IN ('U', 'V')
I have a query that pulls the information from the sys tables to produce a list of the new objects that have been created in our environment. What I need to do is the last part of the query needs to be able to look at another table and pull the 3 most current records and use the date from those records to show only the objects that have been created since those 3 dates. In my testing I keep running into "Subquery returned more than 1 value" Any help would be greatly appreciated.
EDIT:
I am currently running SQL 2008 R2.
The query runs now as is, but only pulls the most recent date, I need it to pull everything from the last 3 dates.
SELECT
a.name AS ObjectName, b.name AS ParameterName, c.name AS DataType,
b.isnullable AS [Allow Nulls?], a.crdate AS CreateDate,
CASE WHEN d .name IS NULL THEN 0 ELSE 1 END AS [PKey?],
CASE WHEN e.parent_object_id IS NULL THEN 0 ELSE 1 END AS [FKey?],
CASE WHEN e.parent_object_id IS NULL THEN '-' ELSE g.name END AS [Ref Table],
CASE WHEN h.value IS NULL THEN '-' ELSE h.value END AS Description,
c.length AS FieldSize, a.replinfo AS IsReplicated,
CASE a.xtype WHEN 'V' THEN 'View' WHEN 'P' THEN 'StoredProcedure' WHEN 'FN' THEN 'ScalarFunction' WHEN 'F' THEN 'ForeignKey' WHEN 'U' THEN 'Table' WHEN
'TR' THEN 'Trigger' WHEN 'TT' THEN 'TableType' WHEN 'PK' THEN 'PrimaryKey' END AS ObjectType
FROM
sys.sysobjects AS a
INNER JOIN sys.syscolumns AS b ON a.id = b.id
INNER JOIN sys.systypes AS c ON b.xtype = c.xtype
LEFT OUTER JOIN
(SELECT so.id, sc.colid, sc.name
FROM
sys.syscolumns AS sc
INNER JOIN sys.sysobjects AS so ON so.id = sc.id
INNER JOIN sys.sysindexkeys AS si ON so.id = si.id AND sc.colid = si.colid
WHERE (si.indid = 1)) AS d ON a.id = d.id AND b.colid = d.colid
LEFT OUTER JOIN sys.foreign_key_columns AS e ON a.id = e.parent_object_id AND b.colid = e.parent_column_id
LEFT OUTER JOIN sys.objects AS g ON e.referenced_object_id = g.object_id
LEFT OUTER JOIN sys.extended_properties AS h ON a.id = h.major_id AND b.colid = h.minor_id
WHERE (a.type = 'U' OR
a.type = 'V' OR
a.type = 'F' OR
a.type = 'PK' OR
a.type = 'P' OR
a.type = 'FN' OR
a.type = 'TT' OR
a.type = 'TR') AND
(a.crdate >
(SELECT TOP (1) DeployDate
FROM OtherTable.dbo.Tracking
ORDER BY DeployDate DESC))
ORDER BY CreateDate DESC
If I'm understanding your question correctly, you want the minimum of the last 3 dates in the tracking table.
If so, you could do something like this...
(a.crdate >
(SELECT Min(topthree.DeployDate)
FROM (select Top 3 DeployDate
From dbo.Tracking
ORDER BY DeployDate DESC
) as topthree
)
)
How can i club both the select count and select columns with one statement?
If you are just looking to see what "shape" your tables are in, something like this would work. But if you're wanting to know column/row counts for a given query, it may be possible but I don't know how to do it
; WITH ROW_COUNTS AS
(
SELECT
s.[Name] as [SchemaName]
, t.[name] as [TableName]
, SUM(p.rows) as [RowCounts]
FROM
sys.schemas s
LEFT JOIN
sys.tables t
ON s.schema_id = t.schema_id
LEFT JOIN
sys.partitions p
ON t.object_id = p.object_id
LEFT JOIN
sys.allocation_units a
ON p.partition_id = a.container_id
WHERE
p.index_id in(0,1) -- 0 heap table , 1 table with clustered index
AND p.rows is not null
AND a.type = 1 -- row-data only , not LOB
GROUP BY
s.[Name]
, t.[name]
)
, COLUMN_COUNTS AS
(
SELECT
s.[Name] as [SchemaName]
, t.[name] as [TableName]
, COUNT(c.column_id) as [ColumnCounts]
FROM
sys.schemas s
INNER JOIN
sys.tables t
ON s.schema_id = t.schema_id
INNER JOIN
sys.columns c
ON C.object_id = T.object_id
GROUP BY
s.[Name]
, t.[name]
)
SELECT
CC.SchemaName
, CC.TableName
, RC.RowCounts
, CC.ColumnCounts
FROM
COLUMN_COUNTS CC
INNER JOIN
ROW_COUNTS RC
ON RC.SchemaName = CC.SchemaName
AND RC.TableName = CC.TableName
ORDER BY
1,2
Results run against master
SchemaName TableName RowCounts ColumnCounts
dbo Hold_Cluster_Status 0 10
dbo MSreplication_options 3 6
dbo spt_fallback_db 0 8
dbo spt_fallback_dev 0 10
dbo spt_fallback_usg 0 9
dbo spt_monitor 1 11
dbo spt_values 2506 6
Using a COUNT() window aggregate you should be able to accomplish what you are looking to do. However, the DISTINCT against a very large table is not likely to be very performant:
SELECT DISTINCT a, b, c, COUNT(*) OVER (PARTITION BY 1) FROM <tablename>;
Another option would be but you are touching the table twice:
SELECT a,b,c, MyCount
FROM <tablename>
CROSS JOIN
(SELECT COUNT(*) AS MyCount
FROM <tablename>
)
I'm not 100% ure what you want, but here is a possible example...
SELECT
a,
b,
c,
(SELECT COUNT(*) FROM yourTable) as table_count
FROM
yourTable
I am trying to develop a query to insert unique records but am receiving the SQL Server Primary Key error for trying to insert duplicate records. I was able to insert some values with this query but not for this record (score_14).
So now I am trying to find duplicate record with the following query. The challenge is that my PK is based on 3 columns: StudentID, MeasureDate, and MeasureID--all from a different table not mentioned below.
But this only shows me count--instead I want to just return records with count > 1. How do I do that?
select count(a.score_14) as score_count, A.studentid, A.measuredate, B.measurename+' ' +B.LabelName
from [J5C_Measures_Sys] A
join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
join sysobjects so on so.name = 'J5C_Measures_Sys'
join syscolumns sc on so.id = sc.id
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
where so.type = 'u' and sc.name = 'score_14' and a.score_14 is not null
AND A.STUDENTID IS NOT NULL AND A.MEASUREDATE IS NOT NULL AND B.MEASURENAME IS NOT NULL
--and count(a.score_14)>1
group by a.studentid, a.measuredate, B.measurename, B.LabelName, A.score_14
having count(a.score_14) > 1
Beth is correct - here's my re-write of your query:
SELECT a.studentid, a.measuredate, a.measureid
from [J5C_Measures_Sys] A
GROUP BY a.studentid, a.measuredate, a.measureid
HAVING COUNT(*) > 1
Previously:
SELECT a.studentid, a.measuredate, a.measureid
from [J5C_Measures_Sys] A
join [J5C_ListBoxMeasures_Sys] B on A.MeasureID = B.MeasureID
join sysobjects so on so.name = 'J5C_Measures_Sys'
AND so.type = 'u'
join syscolumns sc on so.id = sc.id
and sc.name = 'score_14'
join [J5C_MeasureNamesV2_Sys] v on v.Score_field_id = sc.name
where a.score_14 is not null
AND B.MEASURENAME IS NOT NULL
GROUP BY a.studentid, a.measuredate, a.measureid
HAVING COUNT(*) > 1
you need to take A.score_14 out of your group by clause if you want to count it