How to get parameter values for dm_exec_sql_text - sql-server

I'm running the following statement to see what queries are executing in sql server:
select *
from sys.dm_exec_requests r
cross apply sys.dm_exec_sql_text(r.sql_handle)
where r.database_id = DB_ID('<dbname>')
The sql text that comes back is parameterized:
(#Parm0 int) select * from foo where foo_id = #Parm0
Is there any way to get the values for the parameters that the statement is using? Say by joining to another table perhaps?

Edit : Remus is correct, this will only bring out the compiled versions on the first time that the query plan hit the cache, not subsequent runs.
You should be able to get the parameters from the query plan, since it contains the last parameters used. Altering your code:
select *
from sys.dm_exec_requests r
cross apply sys.dm_exec_query_plan(plan_handle) as qp
cross apply sys.dm_exec_sql_text(r.sql_handle)
where r.database_id = DB_ID('<dbname>')
You will find the final column of the query plan is query_plan, an xml version of the query plan which you can manually inspect, at the bottom of the XML are the parameters, or if you fancy the challenge use XML parsing and XQuery to pull out the ParameterList tags

A query that give the login name, hour of execution and query as text of last events, if you can give a hand to the join of sys.dm_exec_query_stats, but it works
SELECT distinct
s.login_name,
qs.creation_time
,SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset END
- qs.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_sessions S
LEFT JOIN sys.dm_exec_connections AS c ON S.session_id = c.session_id
,sys.dm_exec_query_stats QS --qs on c.most_recent_sql_handle = qs.sql_handle
OUTER APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE ST.text LIKE '%yourKeyWord%' and s.login_name <> 'NT SERVICE\SQLSERVERAGENT'
order by qs.creation_time desc

In case someone stumble upon this thread looking for a proper solution (which the other answers sadly lack), I found this helpful post from mssqltips.
I cleaned-up and tweaked the query a little bit to make this one:
-- cleanup
IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
DROP TABLE #compiledValue
GO
-- Prepare temp table #compiledValue
SELECT
OBJECT_NAME(est.objectid) ObjectName,
DB_NAME(est.dbid) DBName,
eqs.last_execution_time,
est.text,
(eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
(IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
TRY_CONVERT(XML,
SUBSTRING(etqp.query_plan,
CHARINDEX('<ParameterList>',etqp.query_plan),
CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params
INTO #compiledValue
FROM sys.dm_exec_query_stats eqs
CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp
SELECT
cvalue.last_execution_time,
cvalue.DBName,
cvalue.ObjectName,
SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
pc.compiled.value('#Column', 'nvarchar(128)') AS Parameterlist,
pc.compiled.value('#ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
FROM #compiledValue cvalue
OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
ORDER BY cvalue.last_execution_time DESC
GO
-- cleanup
DROP TABLE #compiledValue
GO
It works quite well, and each parameters will have its own line.
For instance:

If you are using a version prior to SQL Server 2012 or Amazon RDS where the TRY_CONVERT function does not exist, this is a variation of the Indigo query that will work.
-- cleanup
IF OBJECT_ID('tempdb..#compiledValue') IS NOT NULL
DROP TABLE #compiledValue
GO
-- Prepare temp table #compiledValue
SELECT
OBJECT_NAME(est.objectid) ObjectName,
DB_NAME(est.dbid) DBName,
eqs.last_execution_time,
est.text,
(eqs.statement_start_offset / 2) + 1 AS statement_start_offset,
(IIF(eqs.statement_end_offset = -1, DATALENGTH(est.text), eqs.statement_end_offset) - eqs.statement_start_offset) / 2 + 1 AS statement_end_offset,
--TRY_CONVERT(XML,
-- SUBSTRING(etqp.query_plan,
-- CHARINDEX('<ParameterList>',etqp.query_plan),
-- CHARINDEX('</ParameterList>',etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>',etqp.query_plan) )) AS statement_params,
CASE
WHEN CHARINDEX('<ParameterList>', etqp.query_plan) > 0
THEN CONVERT(XML,
SUBSTRING(etqp.query_plan,
CHARINDEX('<ParameterList>', etqp.query_plan),
CHARINDEX('</ParameterList>', etqp.query_plan) + LEN('</ParameterList>') - CHARINDEX('<ParameterList>', etqp.query_plan) ))
ELSE NULL
END AS statement_params
INTO #compiledValue
FROM sys.dm_exec_query_stats eqs
CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) est
CROSS APPLY sys.dm_exec_text_query_plan(eqs.plan_handle, eqs.statement_start_offset, eqs.statement_end_offset) etqp
SELECT
cvalue.last_execution_time,
cvalue.DBName,
cvalue.ObjectName,
SUBSTRING(cvalue.text,cvalue.statement_start_offset,cvalue.statement_end_offset) AS sql_text,
pc.compiled.value('#Column', 'nvarchar(128)') AS Parameterlist,
pc.compiled.value('#ParameterCompiledValue', 'nvarchar(128)') AS [compiled Value]
FROM #compiledValue cvalue
OUTER APPLY cvalue.statement_params.nodes('//ParameterList/ColumnReference') AS pc(compiled)
WHERE cvalue.text NOT LIKE '%#compiledValue%' -- ignore these queries based on temp table name
ORDER BY cvalue.last_execution_time DESC
GO
-- cleanup
DROP TABLE #compiledValue
GO

Related

Query Performance issues :query case entity (Incident )for Dynamics CRM SSRS Report

I have written below query for dynamics crm- SSRS Report, but it takes too long time for execution (approx. 6 min).
Query :
select ticketnumber, Title, zon_requeststatusname,
FI.owneridname, zon_applicationname, zon_applicationareaname,
LastLogChanged, zon_requestorname , FI.createdon, FI.createdbyname,
isescalatedname, zon_ordername, DATEDIFF(DAY,GETDATE(),
FI.createdon) as AgingPeriod from filteredincident FI left outer join
(select top 1 zon_case, max(createdon) as LastLogChanged from
Filteredzon_caselog group by createdon,zon_case order by 2 desc )CL
on FI.incidentid= CL.zon_case
where DATEDIFF(day,FI.createdon ,GETDATE()) = #CreatedInLast and DATEDIFF(day,FI.modifiedon ,GETDATE()) = #ModifiedSince
Same Queries without Filtered view :(but don't want to use , because we will loose security benefit)
DECLARE #CreatedInLast INT
DECLARE #ModifiedSince INT
SET #ModifiedSince = 1
SET #CreatedInLast = 7
SELECT ticketnumber, Title, zon_requeststatusname, FI.owneridname,
zon_applicationname, zon_applicationareaname, --MAX(CL.modifiedon),
zon_requestorname , FI.createdon, FI.createdbyname,
isescalatedname, zon_ordername,
DATEDIFF(DAY,GETDATE(), FI.createdon) as AgingPeriod FROM filteredincident FI (NOLOCK) LEFT OUTER JOIN zon_caselog CL (NOLOCK)
on FI.incidentid= CL.zon_case AND CL.modifiedon >= GETDATE()-
#ModifiedSince WHERE FI.createdon >= GETDATE()- #CreatedInLast
GROUP BY ticketnumber, Title, zon_requeststatusname, FI.owneridname, zon_applicationname, zon_applicationareaname,
zon_requestorname , FI.createdon, FI.createdbyname,
isescalatedname, zon_ordername
I already run DBCC DBREINDEX and DBCC INDEXDEFRAG.
Please advise me, what's need to improve above queries.
Filteredview will join the select query with POA table internally to maintain the CRM security model in resultset.
I would recommend you to take a look at the size of PrincipalObjectAccess (POA) table & consider cleaning it up.

SQL Server : Cross Join in GreenPlum (Pre-LATERAL version of Postgres)

I'm attempting to convert the following SQL Server query into a GreenPlum version of the query:
INSERT INTO #TMP1 (part_id, file_id, location, measure_date)
SELECT DISTINCT
pt.part_id, qf.file_id, qf.edl_desc, pt.measure_date
FROM
part pt WITH (NOLOCK)
INNER JOIN
file_model qm with (nolock) on qm.file_model_id = pt.file_model_id
INNER JOIN
file qf with (nolock) on qf.file_id = qm.file_id;
INSERT INTO #part_list (file_id, part_id, measure_date)
SELECT DISTINCT
t1.file_id, k.part_id, k.measure_date
FROM
#TMP1 t1 WITH (NOLOCK)
CROSS APPLY
(SELECT DISTINCT TOP (300)
t2.part_id, t2.measure_date
FROM
#TMP1 t2 WITH (NOLOCK)
WHERE
t1.file_id = t2.file_id and t1.location = t2.location
ORDER BY
t2.measure_date DESC) k
WHERE
t1.measure_date >= dateadd(day, 30, getdate());
The idea here being that the final table contains the most recent up to 300 parts for all parts programs that are active (ie manufactured something) in the last 30 days.
Per the answers to this question, I am aware that LATERAL JOIN would do it, except my organization is using an older version of Postgres that does not have LATERAL, so I was left with implementing the following function instead:
CREATE FUNCTION BuildActiveParts(p_day INT, p_n INT)
RETURNS SETOF RECORD --TABLE (part_id bigint,file_id int, measure_date timestamp, location varchar(255))
AS $$
DECLARE
part_active RECORD;
part_list RECORD;
BEGIN
FOR part_active IN
SELECT DISTINCT qf.file_id, qf.location
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id WHERE pt.measure_date >= current_date - p_day LOOP
FOR part_list IN
SELECT DISTINCT pt.part_id, qf.file_id, pt.measure_date, qf.location
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id WHERE qf.file_id = part_active.file_id
AND qf.location = part_active.location
ORDER BY pt.measure_date DESC LIMIT p_n LOOP
RETURN NEXT part_list;
END LOOP;
END LOOP;
END
$$ LANGUAGE plpgsql;
-- Later used in:
--Build list of all active programs in last p_day days. This temporary table is a component of a larger function that produces a table based on this and other other calculations, called daily.
-- Note: this insert yields 'function cannot execute because it accesses relation'
INSERT INTO TMP_part_list ( part_id, file_id, measure_date, location)
SELECT DISTINCT * FROM BuildActiveParts(p_day, p_n) AS active_parts (part_id int, file_id text, measure_date timestamp, location text )
;
Unfortunately, this function is used in inserts to another table (an unavoidable reality of my business requirements), so while the function returns nice happy results when run in isolation, I get a big angry function cannot execute on segment because it accesses relation when I try to use it for its intended purpose. While I've seen suggestions to the effect of "make a VIEW instead", that's not really an option because a view resulting from the script this functionality is a part of would take too long to query.
What can I do, beyond embarking on a months-long excursion through a jungle of red tape to convince my organization to update their stuff, to resolve this?
Edit: Here are some attempts based on comments:
Attempt with function, did not work because of function cannot execute on segment because it accesses relation:
DROP FUNCTION IF EXISTS BuildRecentParts(TEXT, TEXT, INT);
CREATE FUNCTION BuildRecentParts(file_id TEXT, location_in TEXT, p_n INT)
RETURNS SETOF RECORD --TABLE (measure_date timestamp, part_id bigint)
AS $$
DECLARE
part_list RECORD;
BEGIN
FOR part_list IN
SELECT DISTINCT pt.measure_date, pt.part_id
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id
WHERE qf.file_id = file_id
AND qf.edl_desc = location_in
ORDER BY pt.measure_date DESC LIMIT p_n LOOP
RETURN NEXT part_list;
END LOOP;
END
$$ LANGUAGE plpgsql;
SELECT DISTINCT qf.file_id, qf.edl_desc, (SELECT pti.measure_date, pti.part_id FROM part pti
INNER JOIN file_model qmi on qmi.file_model_id = pti.file_model_id
INNER JOIN file qfi on qfi.file_id = qmi.file_id
WHERE qfi.file_id = qf.file_id
AND qfi.edl_desc = qf.edl_desc
ORDER BY pti.measure_date DESC LIMIT 300)
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id
WHERE pt.measure_date >= current_date - 30 ;
Attempt without function, will not work because subquery has multiple columns:
CREATE TEMPORARY TABLE TMP_TMP1 (part_id bigint, file_id varchar(255), location varchar(255), measure_date timestamp) DISTRIBUTED BY (part_id);
INSERT INTO TMP_TMP1 (part_id, file_id, location, measure_date)
SELECT DISTINCT pt.part_id, qf.file_id, qf.edl_desc, pt.measure_date
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id;
ANALYZE TMP_TMP1;
SELECT DISTINCT t1.file_id, t1.location, (SELECT t2.measure_date, t2.part_id FROM TMP_TMP1 t2
WHERE t2.file_id = t1.file_id
AND t2.location = t1.location
ORDER BY t2.measure_date DESC LIMIT 300)
FROM TMP_TMP1 t1
WHERE t1.measure_date >= current_date - 30;
I also attempted a recursive CTE, but found that that was unsupported.
Between answers here and from architects at my organization, we decided that we have struck a GreenPlum limitation that would be too costly to overcome, the logic that performs the Cross Join will be shifted to the R script that calls the stored procedure that this functionality would have been a part of.
Well, Greenplum doesn't have dirty reads so you can't implement the nolock hint you have. That is probably a good thing too. I would recommend removing that from SQL Server too.
I think the best solution is to use an Analytical function here instead of that function or even a correlated subquery which Greenplum supports. It is also more efficient in SQL Server to use this approach.
SELECT sub2.part_id, sub2.location, sub2.measure_date
FROM (
SELECT sub1.part_id, sub1.location, sub1.measure_date, row_number() over(partition by sub1.part_id order by sub1.measure_date desc) as rownum
FROM (
SELECT pt.part_id, qf.edl_desc as location, pt.measure_date
FROM part pt
INNER JOIN file_model qm on qm.file_model_id = pt.file_model_id
INNER JOIN file qf on qf.file_id = qm.file_id
WHERE pt.measure_date >= (now() - interval '30 days')
GROUP BY pt.part_id, qf.edl_desc, pt.measure_date
) AS sub1
) as sub2
WHERE sub2.rownum <= 300;
Now, I had to guess at your data because it looks like you could get into trouble with your original query if you have multiple qf.qcc_file_desc values because your original group by includes this. If you had multiple values, then things would get ugly.
I'm also not 100% sure on the row_number function without knowing your data. It might be this instead:
row_number() over(partition by sub1.part_id, sub1.location order by sub1.measure_date desc)

Create View - Declare a variable

I am creating a view that is using that STUFF function. I want to put the result of STUFF in a variable for my view. The problem I am having is declaring my variable. It gives me the message "Incorrect Syntax near 'DECLARE'. Expecting '(' or SELECT." I already have the '(' in there. I have tried putting a BEGIN before it. I have tried putting it after the SELECT word. But nothing seems to work and I cannot find a solution in my search. I am using SQL Server 2012
CREATE VIEW [AQB_OB].[GISREQUESTEDBURNS]
AS
(DECLARE #CONDITIONS AS varchar(20)
SET #CONDITIONS = (SELECT DISTINCT BD.[RequestedBurnsID]
,[ConditionsReasonsID] = STUFF((SELECT ', ' + CONVERT(VARCHAR (20),[ConditionsReasonsID]) FROM [AQB_OB].[BurnDecisions] WHERE [RequestedBurnsID]= BD.[RequestedBurnsID] ORDER BY [RequestedBurnsID] ASC
FOR XML PATH ('')) , 1 , 1, '') FROM
[AQB_OB].[BurnDecisions] BD)
SELECT RB.[RequestedBurnsID] AS REQUESTEDBURNID
,BUY.[BurnYear] AS BURNYEAR
,CY.[CurrentYear] AS CURRENTYEAR
,RB.[BurnSitesID] AS BURNSITESID
,[BurnerID] AS BURNERID
,[Contact] AS CONTACT
,[BurnDecision] AS BURNDECISION
,RB.[Comment] AS COMMENT
,#CONDITIONS AS CONDITIONS
FROM [AQB_MON].[AQB_OB].[RequestedBurns] RB
LEFT join AQB_MON.[AQB_OB].[PileDryness] PD on RB.[PileDrynessID] = PD.[PileDrynessID]
inner join AQB_MON.[AQB_OB].[BurnYear] BUY on BUY.BurnYearID = BP.BurnYearID
inner join AQB_MON.[AQB_OB].[CurrentYear] CY on CY.CurrentYearID = BUY.CurrentYearID
GO
You can't declare variables in a view. Could you make it into a function or stored procedure?
Edit - you might also be able to put something into a CTE (Common Table Expression) and keep it as a view.
e.g.
WITH conditions as
(
... do the STUFF here
)
SELECT blah
FROM blah
INNER JOIN conditions
(or CROSS JOIN conditions if its just one row, I can't quite decipher what your data is like)
Here is a sample query that uses a CTE (Common Table Expression) to nicely emulate internal variable construction, as described by James Casey. You can test-run it in your version of SQL Server.
CREATE VIEW vwImportant_Users AS
WITH params AS (
SELECT
varType='%Admin%',
varMinStatus=1)
SELECT status, name
FROM sys.sysusers, params
WHERE status > varMinStatus OR name LIKE varType
SELECT * FROM vwImportant_Users
yielding output:
status name
12 dbo
0 db_accessadmin
0 db_securityadmin
0 db_ddladmin
also via JOIN
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers INNER JOIN params ON 1=1
WHERE status > varMinStatus OR name LIKE varType
also via CROSS APPLY
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers CROSS APPLY params
WHERE status > varMinStatus OR name LIKE varType
Or use a CTE (common table expression) as subselect like:
WITH CTE_Time(Clock)
AS(
SELECT 11 AS [Clock] -- set var
)
SELECT
DATEPART(HOUR, GETDATE()) AS 'actual hour',
CASE
WHEN DATEPART(HOUR, GETDATE()) >= (SELECT [Clock] FROM CTE_Time) THEN 'after'
ELSE 'before'
END AS [Data]
Try put the condition subquery directly inside the the view select statement. you may CAST the XML to VARCHAR(20).
CREATE VIEW [AQB_OB].[GISREQUESTEDBURNS]
AS
SELECT RB.[RequestedBurnsID] AS REQUESTEDBURNID
,BUY.[BurnYear] AS BURNYEAR
,CY.[CurrentYear] AS CURRENTYEAR
,RB.[BurnSitesID] AS BURNSITESID
,[BurnerID] AS BURNERID
,[Contact] AS CONTACT
,[BurnDecision] AS BURNDECISION
,RB.[Comment] AS COMMENT,
(
SELECT DISTINCT BD.[RequestedBurnsID],
[ConditionsReasonsID] = STUFF((SELECT ', ' + CONVERT(VARCHAR (20), [ConditionsReasonsID]) FROM [AQB_OB].[BurnDecisions]
WHERE [RequestedBurnsID]= BD.[RequestedBurnsID] ORDER BY [RequestedBurnsID] ASC
FOR XML PATH ('')) , 1 , 1, '') FROM
[AQB_OB].[BurnDecisions] BD
) AS CONDITIONS
FROM [AQB_MON].[AQB_OB].[RequestedBurns] RB
LEFT join AQB_MON.[AQB_OB].[PileDryness] PD on RB.[PileDrynessID] = PD.[PileDrynessID]
inner join AQB_MON.[AQB_OB].[BurnYear] BUY on BUY.BurnYearID = BP.BurnYearID
inner join AQB_MON.[AQB_OB].[CurrentYear] CY on CY.CurrentYearID = BUY.CurrentYearID

Could not find server ‘DATABASE_NAME′ in sys.servers error

The code below is embedded in a .sql file in a vb.net project. It gives me an error:
Could not find server ‘DATABASE_NAME′ in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.
I checked in sys.server and the LinkedDatabaseName is returned if i do a select * from sys.servers
Here is the code where I get the error....
-----------------------------------
-- Obs Set Obs Set Obs Item Xref
-----------------------------------
-- STEP 1: txmr_TABLE1 to exp_TABLE1
DELETE FROM LinkedDatabaseName...exp_TABLE1
Select distinct newid() as GUID,
b.ObsSetCode as 'parObsSetCode',
c.ObsSetCode as 'chObsSetCode',
d.ObsItemCode as 'chObsItemCode'
Into #tmp_exp_TABLE1
From $$DATABASE_NAME$$..txmr_TABLE1 a
Inner Join $$DATABASE_NAME$$..txmr_obs_set b On a.parObsSetGUID = b.GUID
Left Join $$DATABASE_NAME$$..txmr_obs_set c On a.chObsSetGUID = c.GUID
Left Join $$DATABASE_NAME$$..txmr_obs_item d On a.chObsItemGUID = d.GUID
Order By b.ObsSetCode
Select * From #tmp_exp_TABLE1
EXEC $$DATABASE_NAME$$..dbo.txmr_ExtractPOCIS '#tmp_exp_TABLE1',
'$$DATABASE_NAME$$.dbo.txmr_TABLE1_chg',
#FromVersion,
#ToVersion;
INSERT INTO LinkedDatabaseName...exp_TABLE1 (GUID, parObsSetCode, chObsSetCode, chObsItemCode)
SELECT GUID, parObsSetCode, chObsSetCode, chObsItemCode
FROM #tmp_exp_TABLE1
ORDER BY parObsSetCode, chObsSetCode;
DROP TABLE #tmp_exp_TABLE1;
SELECT COUNT(*), 'exp_TABLE1' FROM LinkedDatabaseName...exp_TABLE1;
-- STEP 2: txmr_TABLE1_chg to exp_TABLE1_chg
DELETE FROM LinkedDatabaseName...exp_TABLE1_chg;
INSERT INTO LinkedDatabaseName...exp_TABLE1_chg (ChangeID, DateModified, parObsSetCode, chObsSetCode, chObsItemCode, RationaleLink, RationaleFreeText)
SELECT a.GUID as 'ChangeID',
a.DateModified as 'DateModified',
b.ObsSetCode as 'parObsSetCode',
c.ObsSetCode as 'chObsSetCode',
d.ObsItemCode as 'chObsItemCode',
r.RationaleID as 'RationaleLink',
a.RationaleFreeText as 'RationaleFreeText'
FROM $$DATABASE_NAME$$..txmr_TABLE1_chg a
INNER JOIN $$DATABASE_NAME$$..txmr_obs_set b ON a.parObsSetGUID = b.GUID
LEFT JOIN $$DATABASE_NAME$$..txmr_obs_set c ON a.chObsSetGUID = c.GUID
LEFT JOIN $$DATABASE_NAME$$..txmr_obs_item d ON a.chObsItemGUID = d.GUID
LEFT JOIN $$DATABASE_NAME$$..txmr_rationale r ON a.RationaleGUID = r.GUID
WHERE #StartDate <= a.DateModified AND #EndDate > a.DateModified
ORDER BY a.DateModified, b.ObsSetCode;
SELECT COUNT(*), 'exp_TABLE1_chg'
FROM LinkedDatabaseName...exp_TABLE1_chg;
The problem is that there are inconsistent usages of the $$DATABASE_NAME$$ substitution string. In most cases it is used to reference a specific database
$$DATABASE_NAME$$..txmr_TABLE1
but in the exec string:
EXEC $$DATABASE_NAME$$..dbo.txmr_ExtractPOCIS
there is one too many periods, which means that it is now referencing a different server and not a database.
Changing this statement to:
EXEC $$DATABASE_NAME$$.dbo.txmr_ExtractPOCIS
should resolve the problem.

Join subquery with min

I'm pulling my hair out over a subquery that I'm using to avoid about 100 duplicates (out of about 40k records). The records that are duplicated are showing up because they have 2 dates in h2.datecreated for a valid reason, so I can't just scrub the data.
I'm trying to get only the earliest date to return. The first subquery (that starts with "select distinct address_id", with the MIN) works fine on it's own...no duplicates are returned. So it would seem that the left join (or just plain join...I've tried that too) couldn't possibly see the second h2.datecreated, since it doesn't even show up in the subquery. But when I run the whole query, it's returning 2 values for some ipc.mfgid's, one with the h2.datecreated that I want, and the other one that I don't want.
I know it's got to be something really simple, or something that just isn't possible. It really seems like it should work! This is MSSQL. Thanks!
select distinct ipc.mfgid as IPC, h2.datecreated,
case when ad.Address is null
then ad.buildingname end as Address, cast(trace.name as varchar)
+ '-' + cast(trace.Number as varchar) as ONT,
c.ACCOUNT_Id,
case when h.datecreated is not null then h.datecreated
else h2.datecreated end as Install
from equipmentjoin as ipc
left join historyjoin as h on ipc.id = h.EQUIPMENT_Id
and h.type like 'add'
left join circuitjoin as c on ipc.ADDRESS_Id = c.ADDRESS_Id
and c.GRADE_Code like '%hpna%'
join (select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment)
as h2 on c.address_id = h2.address_id
left join (select car.id, infport.name, carport.number, car.PCIRCUITGROUP_Id
from circuit as car (NOLOCK)
join port as carport (NOLOCK) on car.id = carport.CIRCUIT_Id
and carport.name like 'lead%'
and car.GRADE_Id = 29
join circuit as inf (NOLOCK) on car.CCIRCUITGROUP_Id = inf.PCIRCUITGROUP_Id
join port as infport (NOLOCK) on inf.id = infport.CIRCUIT_Id
and infport.name like '%olt%' )
as trace on c.ccircuitgroup_id = trace.pcircuitgroup_id
join addressjoin as ad (NOLOCK) on ipc.address_id = ad.id
The typical approach to only getting the lowest row is one of the following. You didn't bother to specify what version of SQL Server you're using, what you want to do with ties, and I have little interest to try to work this into your complex query, so I'll show you an abstract simplification for different versions.
SQL Server 2000
SELECT x.grouping_column, x.min_column, x.other_columns ...
FROM dbo.foo AS x
INNER JOIN
(
SELECT grouping_column, min_column = MIN(min_column)
FROM dbo.foo GROUP BY grouping_column
) AS y
ON x.grouping_column = y.grouping_column
AND x.min_column = y.min_column;
SQL Server 2005+
;WITH x AS
(
SELECT grouping_column, min_column, other_columns,
rn = ROW_NUMBER() OVER (ORDER BY min_column)
FROM dbo.foo
)
SELECT grouping_column, min_column, other_columns
FROM x
WHERE rn = 1;
This subqery:
select distinct address_id, equipment_id,
min(datecreated) as datecreated, comment
from history where comment like 'MAC: 5%' group by equipment_id, address_id, comment
Probably will return multiple rows because the comment is not guaranteed to be the same.
Try this instead:
CROSS APPLY (
SELECT TOP 1 H2.DateCreated, H2.Comment -- H2.Equipment_id wasn't used
FROM History H2
WHERE
H2.Comment LIKE 'MAC: 5%'
AND C.Address_ID = H2.Address_ID
ORDER BY DateCreated
) H2
Switch that to OUTER APPLY in case you want rows that don't have a matching desired history entry.

Resources