SQL alternative to using while loop to create calculated measure - sql

I am creating a field by performing some calculations.
Then in the next iteration I use that result to compute a new value. Currently doing this with a WHILE loop. Any other way?
I have tried LAG and Partition and even a recursive CTE but could not achieve the same outcome:
DECLARE #Period INT = 2;
DECLARE #MaxPeriod INT;
SELECT #MaxPeriod = Periods FROM dbo.Engine (NOLOCK);
WHILE (#Period <= #MaxPeriod)
BEGIN
WITH CTE AS (
SELECT
A.ProjectId, A.TypeId, A.Trial, A.Period,
((B.ValueA * (COALESCE(B.FactorCalculated, 0) + 1)) +
(A.ValueA * 0)) / A.ValueA AS FactorCalculated
FROM dbo.PenetrationResults A (NOLOCK)
INNER JOIN dbo.PenetrationResults B (NOLOCK)
ON A.ProjectId = B.ProjectId
AND A.TypeId = B.TypeId
AND A.Trial = B.Trial
AND (A.Period - 1) = B.Period
WHERE A.[Period] = #Period
AND A.ProjectId = #ProjectId
)
UPDATE [target]
SET FactorCalculated = CTE.FactorCalculated
FROM dbo.PenetrationResults AS [target] --(TABLOCK)
INNER JOIN CTE
ON [target].[ProjectId] = CTE.ProjectId AND [target].[TypeId] = CTE.TypeId
AND [target].[Trial] = CTE.Trial
AND [target].[Period] = CTE.Period
SET #Period = #Period + 1
END ;

Well I found a way to make this work using the CTE recursive abilities finally, improved performance 4 x
WITH ncte AS (
-- number the rows sequentially without gaps
SELECT
ProjectId,
TypeId,
Trial,
[Period],
FactorWifiCumulative--,
--FactorConnectedCalc
FROM dbo.PenetrationResults (NOLOCK)
WHERE ProjectId = #ProjectId
), rcte AS (
-- find first row in each group
SELECT *, CAST(0 AS DECIMAL(21,14)) AS Calc
FROM ncte AS base
WHERE Period = 1
UNION ALL
-- find next row for each group from prev rows
SELECT curr.*,
CAST(
(
(
prev.FactorWifiCumulative
*
(
COALESCE(prev.Calc,0)
+ 1
)
)
+
(
curr.FactorWifiCumulative*0
)
)
/
curr.FactorWifiCumulative AS DECIMAL(21,14))
AS Calc
--CAST(prev.Calc * (1 + curr.FactorWifiCumulative / 100) AS DECIMAL(21, 14))
FROM ncte AS curr
INNER JOIN rcte AS prev
ON curr.Period = prev.Period + 1
AND curr.TypeId = prev.TypeId
AND curr.Trial = prev.Trial
)
UPDATE [target]
SET [FactorConnectedCalc] = [Calc]
FROM dbo.PenetrationResults AS [target] (NOLOCK)
INNER JOIN rcte
ON [target].[ProjectId] = rcte.ProjectId
AND [target].[TypeId] = rcte.TypeId
AND [target].[Trial] = rcte.Trial
AND [target].[Period] = rcte.Period
OPTION(MAXRECURSION 0);

Related

MS SQL SERVER PAGING

I did a query which is :
SELECT DISTINCT m.logID
FROM Monitor_data m
inner join Monitor_object o on (o.objID = m.domainID)
inner join Monitor_event e on (e.mainID = m.logID)
WHERE (o.name = #objName
and m.service = #service
and e.statement = #statement
and m.start >= #start
and m.end <= #end)
That allows me to get some id (VARCHAR(50)). But, now I want to make a pagination so I need to modify that query. Unfortunately, I cannot use LIMIT and OFFSET ... I may use ROW_NUMBER but I don't know how :/ It will be great to get a result corresponding to the rows at line n to m. Thus, I will be able to create a paging process easily.
Can someone help me ?
Thank you.
Try this query:
select logID from (
SELECT DISTINCT m.logID,
ROW_NUMBER() over (order by m.start) rn
FROM Monitor_data m
inner join Monitor_object o on (o.objID = m.domainID)
inner join Monitor_event e on (e.mainID = m.logID)
WHERE (o.name = #objName
and m.service = #service
and e.statement = #statement
and m.start >= #start
and m.end <= #end)
) a where rn between (m, n) --here you provide values for limits for rows to return
Above query is based on ROW_NUMBER function in SQL Server, which requires some ordering, so I assumed that m.start will provide an order (I think it start date or something :) ).
Use #PageIndex and PageSize for paging
declare #PageIndex int=1
declare #PageSize int=10
declare #RecordCount int
SET NOCOUNT ON;
SELECT
ROW_NUMBER() OVER (ORDER BY m.logID ) as RowNumber, DISTINCT m.logID
INTO #Results
FROM Monitor_data m
inner join Monitor_object o on (o.objID = m.domainID)
inner join Monitor_event e on (e.mainID = m.logID)
WHERE (o.name = #objName
and m.service = #service
and e.statement = #statement
and m.start >= #start
and m.end <= #end)
SELECT #RecordCount = COUNT(*) FROM #Results
SELECT
*, #RecordCount as RecordCount FROM #Results
WHERE
RowNumber BETWEEN (#PageIndex -1) * #PageSize + 1 AND (((#PageIndex -1) * #PageSize + 1) + #PageSize) - 1
DROP TABLE #Results
I think this is what you want.
Select logId from
(SELECT DISTINCT m.logID, Row_number() over (order by (select null)) as ranking
FROM Monitor_data m
inner join Monitor_object o on (o.objID = m.domainID)
inner join Monitor_event e on (e.mainID = m.logID)
WHERE (o.name = #objName
and m.service = #service
and e.statement = #statement
and m.start >= #start
and m.end <= #end))
where ranking between n and m
ORDER BY ******
OFFSET #ItemsPerPage * (#CurrentPage - 1) ROWS
FETCH NEXT #ItemsPerPage ROWS ONLY
DECLARE #CurrentPage int = 1;
DECLARE #ItemsPerPage int = 10;
SELECT DISTINCT m.logID
FROM Monitor_data m
inner join Monitor_object o on (o.objID = m.domainID)
inner join Monitor_event e on (e.mainID = m.logID)
WHERE (o.name = #objName
and m.service = #service
and e.statement = #statement
and m.start >= #start
and m.end <= #end)
ORDER BY m.logID
OFFSET #ItemsPerPage * (#CurrentPage - 1) ROWS
FETCH NEXT #ItemsPerPage ROWS ONLY
paging Example
DECLARE #myTable TABLE(Id int, Name nvarchar(50),EventDate date);
INSERT INTO #myTable(Id, Name, EventDate)
VALUES (1, 'a', '2018-01-01'),
(2, 'b', '2018-01-02'),
(3, 'c', '2018-01-03'),
(4, 'd', '2018-01-04'),
(5, 'e', '2018-01-05'),
(6, 'f', '2018-01-06');
DECLARE #CurrentPage int = 1;
DECLARE #ItemsPerPage int = 4;
SELECT * FROM #myTable
ORDER BY EventDate DESC
OFFSET #ItemsPerPage * (#CurrentPage - 1) ROWS
FETCH NEXT #ItemsPerPage ROWS ONLY
Starting with 2012, you could use OFFSET and FETCH. Prior to that a solution is to use ROW_NUMBER. However, beware, ROW_NUMBER() approach is very slow. If you don't have a performance problem you can use it.
Whatever the version is, a fast paging is done using TOP N and ordering by your desired columns and also specifying minimum value. ie:
select TOP (#pageSize) * from myTable
where myKeyValue > #minValue
order by myKeyValue;

SQL: LEFT OUTER JOIN not returning any rows

I have a query that is using a LEFT OUTER JOIN to merge 2 data sets. I know both data sets should return data because I ran the superquery and the subquery separately. For some reason, the query is returning zero results. Anyone know why?
Left data:
item FG_lots
447845 E2211
Right data:
candy_lot_check candy_item
L2211 835116
Intended result:
item FG_lots candy_lot_check candy_item
447845 E2211 null null
The result from my broken query (no results):
item FG_lots candy_lot_check candy_item
The query:
--Initialization--
DECLARE #Item NVARCHAR(30) = '447845'
DECLARE #Date datetime = '6/13/2016'
SET DATEFIRST 1;
DECLARE #client NVARCHAR(20)
SET #client = (SELECT i.Uf_ClientName FROM item AS i WHERE i.item = #Item)
DECLARE #count integer
--Query--
SET #count = (CASE
WHEN (#client = 'A' OR #client = 'B')
THEN 4
WHEN #client = 'C'
THEN 3
WHEN #client = 'D'
THEN 5
ELSE
4
END)
SELECT DISTINCT
t.item,
LEFT(t.lot,#count) AS FG_lots,
(CASE
WHEN candylot.candy_lots IS NULL
THEN 'NO MATCH'
ELSE candylot.candy_lots
END) AS candy_lot_check,
(CASE
WHEN candylot.item IS NULL
THEN 'NO MATCH'
ELSE candylot.item
END) AS candy_item
FROM
ISW_LPTrans AS t
LEFT OUTER JOIN
(
SELECT
t.item,
LEFT(t.lot,#count) AS candy_lots,
t.ref_num AS job,
t.ref_line_suf AS suffix
FROM
ISW_LPTrans AS t
INNER JOIN item AS i on i.item = t.item
WHERE
i.product_code = 'RM-Candy' AND
t.trans_date = #Date AND
t.trans_type = 'I' AND
t.ref_num IN
(
SELECT TOP 1
j.job
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
ORDER BY
j.job
)
AND t.ref_line_suf IN
(
SELECT TOP 1
j.suffix
FROM
job AS j
WHERE
j.item = #Item AND
j.job_date = (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, #Date), #Date))
)
GROUP BY
t.item,
t.lot,
t.ref_num,
t.ref_line_suf
) AS candylot ON LEFT(t.lot, #count) = candylot.candy_lots
WHERE
t.ref_num = candylot.job AND
t.ref_line_suf = candylot.suffix AND
t.trans_type = 'F' AND
t.item = #Item AND
t.trans_date = #Date
You've got two 't' aliases, try altering it.
It seems you could rewrite it to make it more readable (joinwise, not indentwise), it could be that something's not right in the logic as well

SQL Server 2008 R2 fails on cast varchar->time

I encountered a weird error in our SQL Server 2008 R2 server. The cast of a varchar to time fails depending on what other columns are used in SELECT clause of the top level statement. Code to reproduce the issue
CREATE FUNCTION [dbo].[explode]
(
#haystack varchar(max),
#separator varchar(8000)
)
RETURNS
#ret TABLE
(
orderCol int identity(1,1),
value varchar(max)
)
AS
BEGIN
declare #index bigint
set #index = charindex(#separator,#haystack)
while #index > 0
begin
insert into #ret (value) values (substring(#haystack,1,#index-1))
set #haystack = substring(#haystack,#index+len(#separator),len(#haystack)-#index-len(#separator)+1)
set #index = charindex(#separator,#haystack)
end
insert into #ret (value) select #haystack
RETURN
END
And the query:
declare #s varchar(1000) = 'a,2015-10-08,1451,1,2,3,4,5,6,7,8,9,10,11;a,2015-10-08,1721,12,13,14,15,16,17,18,19,20,21,22'
declare #units varchar(1000) = 'l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11'
set #units = '#label,#date,#hour,'+#units
;with cte as (select b.value,c.value as unit, a.orderCol as ri from dbo.explode(#s,';') a
cross apply dbo.explode(value,',') b
inner join dbo.explode(#units,',') c
on b.orderCol = c.orderCol),
topCte as (
select c4.unit as unit
,convert(varchar,(case
when len(c3.value) <= 3 then '0' + substring(c3.value,1,1) + ':' + substring(c3.value,2,2)
else (substring(c3.value,1,2) + ':' + substring(c3.value,3,2))
end+':00'),108) as [time]
,c1.value as label
,c2.value as [Date]
,c4.value
from cte c1
inner join cte c2
on c1.ri = c2.ri and c1.unit = '#label' and c2.unit = '#date'
inner join cte c3
on c1.ri = c3.ri and c3.unit = '#hour'
inner join cte c4
on c1.ri = c4.ri and c4.unit not in ('#label','#date','#hour')
)
select unit, label, [date], value, cast([time] as time)
from topCte
This will fail with:
Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.
However when I change the last two lines into any of these, it works correctly:
select unit, label, [date], value, [time]
from topCte
select unit, label, [date], cast([time] as time)
from topCte
I would like to stress that I'm fully aware that this code is sub optimal and I know how to rework this so to avoid the error by rewriting the code still fullfilling business requirement. However this error shouldn't occur in this way and I'm very curious what is triggering it.
I believe there is something wrong in how SQL Server runs the upper query.
I would store the result into a Temporary Table and then cast the result as desired
create table #table_name
(
unit varchar(3),
label varchar(10),
[date] varchar(10),
value varchar(10),
[time] varchar(10),
)
declare #s varchar(1000) = 'a,2015-10-08,1451,1,2,3,4,5,6,7,8,9,10,11;a,2015-10-08,1721,12,13,14,15,16,17,18,19,20,21,22'
declare #units varchar(1000) = 'l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11'
set #units = '#label,#date,#hour,'+#units
;with cte as (select b.value,c.value as unit, a.orderCol as ri from dbo.explode(#s,';') a
cross apply dbo.explode(value,',') b
inner join dbo.explode(#units,',') c
on b.orderCol = c.orderCol),
topCte as (
select c4.unit as unit
,(case
when len(c3.value) <= 3 then '0' + substring(c3.value,1,1) + ':' + substring(c3.value,2,2)
else (substring(c3.value,1,2) + ':' + substring(c3.value,3,2))
end+':00') as [time]
,c1.value as label
,c2.value as [Date]
,c4.value
from cte c1
inner join cte c2
on c1.ri = c2.ri and c1.unit = '#label' and c2.unit = '#date'
inner join cte c3
on c1.ri = c3.ri and c3.unit = '#hour'
inner join cte c4
on c1.ri = c4.ri and c4.unit not in ('#label','#date','#hour')
)
insert into #table_name(unit, label, [date], value, [time])
select unit, label, [date], value, [time]
from topCte
select unit, label, [date], value, cast([time] as time)
from #table_name
The problem is your case expression for the [time] column. If you remove the cast in the select statement you will see values like 14:51:00 which is invalid for time. You are initially converting to a varchar but you don't specify the size which is another issue. There really is no need to convert this to a varchar because it is already a varchar value.
Here is a working version of your code.
declare #s varchar(1000) = 'a,2015-10-08,1451,1,2,3,4,5,6,7,8,9,10,11;a,2015-10-08,1721,12,13,14,15,16,17,18,19,20,21,22'
declare #units varchar(1000) = 'l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11'
set #units = '#label,#date,#hour,'+#units
;with cte as (select b.value,c.value as unit, a.orderCol as ri from dbo.explode(#s,';') a
cross apply dbo.explode(value,',') b
inner join dbo.explode(#units,',') c
on b.orderCol = c.orderCol),
topCte as (
select c4.unit as unit
,
case
when len(c3.value) <= 3 then '0' + substring(c3.value,1,1) + ':' + substring(c3.value,2,2)
else (substring(c3.value,1,2) + ':' + substring(c3.value,3,2))
end
as [time]
,c1.value as label
,c2.value as [Date]
,c4.value
from cte c1
inner join cte c2
on c1.ri = c2.ri and c1.unit = '#label' and c2.unit = '#date'
inner join cte c3
on c1.ri = c3.ri and c3.unit = '#hour'
inner join cte c4
on c1.ri = c4.ri and c4.unit not in ('#label','#date','#hour')
)
select unit, label, [date], value, cast([time] as time)
from topCte

How to tune the following query?

This query gives me the desired result but i can't run this query every time.The 2 loops is costing me.So i need to implement something like view.But the logic has temp tables involved which isn't allowed in views as well.so, is there any other way to store this result or change the query so that it will cost me less.
DECLARE #Temp TABLE (
[SiteID] VARCHAR(100)
,[StructureID] INT
,[row] DECIMAL(4, 2)
,[col] DECIMAL(4, 2)
)
DECLARE #siteID VARCHAR(100)
,#structureID INT
,#struct_row INT
,#struct_col INT
,#rows_count INT
,#cols_count INT
,#row INT
,#col INT
DECLARE structure_cursor CURSOR
FOR
SELECT StructureID
,SiteID
,Cols / 8.5 AS Cols
,Rows / 11 AS Rows
FROM Structure
WHERE SellerID = 658 --AND StructureID = 55
OPEN structure_cursor
FETCH NEXT
FROM structure_cursor
INTO #structureID
,#siteID
,#struct_col
,#struct_row
SELECT #rows_count = 1
,#cols_count = 1
,#row = 1
,#col = 1
WHILE ##FETCH_STATUS = 0
BEGIN
WHILE #row <= #struct_row
BEGIN
WHILE #col <= #struct_col
BEGIN
--PRINT 'MEssage';
INSERT INTO #Temp (
SiteID
,StructureID
,row
,col
)
VALUES (
#siteID
,#structureID
,#rows_count
,#cols_count
)
SET #cols_count = #cols_count + 1;
SET #col = #col + 1;
END
SET #cols_count = 1;
SET #col = 1;
SET #rows_count = #rows_count + 1;
SET #row = #row + 1;
END
SET #row = 1;
SET #col = 1;
SET #rows_count = 1;
FETCH NEXT
FROM structure_cursor
INTO #structureID
,#siteID
,#struct_col
,#struct_row
END
CLOSE structure_cursor;
DEALLOCATE structure_cursor;
SELECT * FROM #Temp
Do this with a set-based operation. I think you just want insert . . . select:
INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT StructureID, SiteID, Cols / 8.5 AS Cols, Rows / 11 AS Rows
FROM Structure
WHERE SellerID = 658;
You should avoid cursors, unless you really need them for some reason (such as calling a stored procedure or using dynamic SQL on each row).
EDIT:
Reading the logic, it looks like you want to insert rows for based on the limits in each row. You still don't want to use a cursor. For that, you need a number generator and master..spt_values is a convenient one, if it has enough rows. So:
with n as (
select row_number() over (order by (select null)) as n
from master..spt_values
)
INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT StructureID, SiteID, ncol.n / 8.5 AS Cols, nrow.n / 11 AS Rows
FROM Structure s JOIN
n ncol
ON ncol.n <= s.struct_col CROSS JOIN
n nrow
ON nrow <= s.struct_row
WHERE SellerID = 658;
You can generate the number of rows and columns and then CROSS APPLY with those, like below. I've left out your SellerID condition.
;WITH Cols
AS
(
SELECT StructureID, SiteID, CAST(Cols / 8.5 AS INT) AS Col
FROM Structure
UNION ALL
SELECT s.StructureID, s.SiteID, Col - 1
FROM Structure s
INNER JOIN Cols c ON s.StructureID = c.StructureID AND s.SiteID = c.SiteID
WHERE Col > 1
)
, Rows
AS
(
SELECT StructureID, SiteID, CAST(Rows / 11 AS INT) AS Row
FROM Structure
UNION ALL
SELECT s.StructureID, s.SiteID, Row - 1
FROM Structure s
INNER JOIN Rows r ON s.StructureID = r.StructureID AND s.SiteID = r.SiteID
WHERE Row > 1
)
--INSERT INTO #Temp (SiteID, StructureID, row, col)
SELECT s.SiteID, s.StructureID, r.Row, c.Col
FROM Structure s
CROSS APPLY Cols c
CROSS APPLY Rows r
WHERE s.StructureID = c.StructureID AND s.SiteID = c.SiteID
AND s.StructureID = r.StructureID AND s.SiteID = r.SiteID
We can do this by using CROSS APPLY and CTE.
CREATE TABLE Structure(SiteID varchar(20), StructureID int,
Cols decimal(18,2), [Rows] decimal(18,2))
INSERT INTO Structure (SiteID, StructureID, Cols, [Rows])
VALUES
('MN353970', 51,17,22),
('MN272252', 52,17,11)
;WITH RowCTE([Rows]) AS
(
SELECT 1
UNION ALL
SELECT 2
),
ColCTE(Cols) AS
(
SELECT 1
UNION ALL
SELECT 2
)
SELECT SiteID, StructureID, R.Rows, C.Cols
FROM Structure s
CROSS APPLY
(
SELECT Cols FROM ColCTE
) C
CROSS APPLY
(
SELECT [Rows] FROM RowCTE
) R
Sql Fiddle Demo

SQL Server 2008 - Update SQL Help Needed

First and foremost, the SQL is handled dynamically by the server, therefore some items in my WHERE clause may look odd to you, please disregard these as they are not an issue.
Per my clients request, they needed to UNION in two other conditions to my update report (/Patients without a Patient Visit/) and (/Patients without a Appointment/). I need help adding in the patients of these two subsets into my final update query. In its present state, it's only adding in the #Temp patients and I need to incorporate the additional patients.
Any help is GREATLY appreciated.
My current SQL update -
DECLARE #Inactive INT
DECLARE #Active INT
DECLARE #PatientProfileId INT
SELECT
#Inactive = MedlistsId
FROM
Medlists
WHERE
TableName = 'PatientProfileStatus'
AND Code = 'I'
SELECT
#Active = MedlistsId
FROM
Medlists
WHERE
TableName = 'PatientProfileStatus'
AND Code = 'A'
CREATE TABLE #Temp
(
PatientName VARCHAR(120) ,
PatientProfileId INT ,
RecentId INT ,
Recent DATETIME
)
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
MAX(pv.PatientVisitId) AS RecentId ,
MAX(pv.Visit) AS Recent
FROM
PatientVisit pv
INNER JOIN PatientProfile pp ON pv.PatientProfileId = pp.PatientProfileId
AND pp.PatientStatusMId = #Active
WHERE
pp.PatientProfileId IN ( SELECT
a.OwnerId
FROM
Appointments a
INNER JOIN PatientProfile pp ON a.OwnerId = pp.PatientProfileId
AND a.ApptKind = 1
AND pp.PatientStatusMId = #Active
GROUP BY
a.OwnerId ,
a.ApptKind
HAVING
MAX(a.ApptStart) < '07/30/2005' )
GROUP BY
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) ,
pp.PatientProfileId
HAVING
MAX(pv.Visit) < '07/30/2005'
/*Patients without a Appointment*/
IF 1 = 1
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
NULL AS RecentId ,
NULL AS Recent
FROM
PatientProfile pp
LEFT JOIN ( SELECT * FROM Medlists WHERE TableName = 'PatientProfileStatus' ) ml1 ON pp.PatientStatusMId = ml1.MedlistsId
LEFT JOIN Appointments a ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
LEFT JOIN PatientVisit pv ON a.PatientVisitId = pv.PatientVisitId
WHERE
ml1.Code = 'A'
AND a.ownerid IS NULL
AND --Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
/*Patients without a Patient Visit*/
IF 0 = 1
INSERT INTO #Temp
SELECT
dbo.FormatName(pp.Prefix , pp.First , pp.Middle , pp.Last , pp.Suffix) AS Name ,
pp.PatientProfileId ,
NULL AS RecentId ,
NULL AS Recent
FROM
PatientProfile pp
LEFT JOIN PatientVisit pv ON pv.PatientProfileid = pp.PatientProfileid
LEFT JOIN ( SELECT * FROM Medlists WHERE TableName = 'PatientProfileStatus' ) ml1 ON pp.PatientStatusMId = ml1.MedlistsId
WHERE
ml1.Code = 'A'
AND pv.patientprofileid IS NULL
AND --Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
DECLARE curPatient CURSOR FORWARD_ONLY READ_ONLY LOCAL
FOR
SELECT
t.PatientProfileId
FROM
#Temp t
JOIN PatientProfile pp ON t.PatientProfileId = pp.PatientProfileId
JOIN PatientVisit pv ON pp.PatientProfileId = pv.PatientProfileId
AND pv.PatientVisitId = t.RecentId
WHERE
--Filter on Age
(
((
'-1' = '-1'
AND '40' = '125'
)
OR ( CAST(( DATEDIFF(DAY , pp.Birthdate , GETDATE()) / 365.25 ) AS INT) BETWEEN ( '-1' ) AND ( '40' ) ))
)
OPEN curPatient
FETCH NEXT FROM curPatient INTO #PatientProfileId
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE
PatientProfile
SET
PatientStatusMId = #Inactive ,
pstatus = 'I'
FROM
PatientProfile P
INNER JOIN #Temp t ON t.PatientProfileID = P.PatientProfileID
WHERE
p.PatientProfileId = #PatientProfileId
FETCH NEXT FROM curPatient INTO #PatientProfileId
END
CLOSE curPatient
DEALLOCATE curPatient
DROP TABLE #Temp
This will limit to patients WITH an appointment
LEFT JOIN Appointments a
ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
This will limit to patients WITH a Visit
LEFT JOIN PatientVisit pv
ON pv.PatientProfileid = pp.PatientProfileid
Try
LEFT OUTER JOIN Appointments a
ON a.Ownerid = pp.PatientProfileId
AND a.ApptKind = 1
Where a.Ownerid is null
LEFT OUTER JOIN PatientVisit pv
ON pv.PatientProfileid = pp.PatientProfileid
Where pv.PatientProfileid is null