Cross apply scope is not visible? - sql-server

Currently I have a udf which returns a table. it returns 3 rows . Each row return the parameter's value *10
Something like (pseudo):
ALTER FUNCTION [dbo].[myUdf]
(
#num int
)
RETURNS #myTable TABLE (h int )
AS
begin
insert into #myTable
SELECT h=#num * 10 UNION
SELECT h=#num * 20 UNION
SELECT h=#num * 30
return #myTable
end
Ok.
Now , in my code I do something like :
select .... ,
has20 = CASE WHEN EXISTS (SELECT 1 FROM dbo.myUdf(A.ID) WHERE h=20)
THEN 0 ELSE 1 end
,
has30 = CASE WHEN EXISTS (SELECT 1 FROM dbo.myUdf(A.ID) WHERE h=30)
THEN 0 ELSE 1 end
...
from A join B...on ...
Where x .. or ..y ... or Exists (select 1 from dbo.myUdf(A.ID) )
Please notice multiple usages :
Ok. So I was told to use Cross apply and so I did :
So let's take a real simple example :
I have this 3 rows of data :
DECLARE #t TABLE(myNum INT)
INSERT #t
VALUES (1), (2), (3)
so let's use cross apply :
SELECT has20 = CASE WHEN EXISTS( SELECT h FROM myCrossApply WHERE mynum=20 )
THEN '1' ELSE '0' END ,
has30 = CASE WHEN EXISTS( SELECT h FROM myCrossApply WHERE mynum=30 )
THEN '1' ELSE '0' END
FROM #t tmp
CROSS APPLY (
-- notice ! in reality there is a udf Table here , I jsut made a simple conversion insted so you can test it.
SELECT h = tmp.myNum * 10 UNION SELECT h = tmp.myNum * 20 UNION SELECT h = tmp.myNum * 30
) myCrossApply
But there is 2 errors here Which I don't know how to solve :
Question #1
It doesn't recognize myCrossApply in the EXISTS clause :
How can I solve this ?
Question #2
Also , the rows are mutipled becuase of the cross apply
For example ( let's remove the unknown exists clause to show the second problem) :
SELECT dummy = tmp.myNum , myCrossApply.h
/*...*/
FROM #t tmp
CROSS APPLY (
SELECT h = tmp.myNum * 10 UNION SELECT h = tmp.myNum * 20 UNION SELECT h = tmp.myNum * 30
) myCrossApply
How can I solve this ?
I just don't want the UDF to be recalculated each time , so they suggested to use cross apply.

myCrossApply is not a real table, it is a reference to a alias for a subset of data.
You would not be able to refer to tmp as a table either.
Here is some code that should use the same logic as your script:
declare #t table(mynum int)
insert #t values(1),(2),(3)
SELECT has20 = myCrossApply.chk1,
has30 = myCrossApply.chk2,
mynum
FROM #t tmp
CROSS APPLY (
SELECT
max(case when h = 20 then 1 else 0 end) chk1,
max(case when h = 30 then 1 else 0 end) chk2
FROM
( SELECT h = tmp.myNum * 10
UNION all
SELECT h = tmp.myNum * 20
UNION all
SELECT h = tmp.myNum * 30) x
) myCrossApply
Result:
has20 has30 mynum
1 1 1
1 0 2
0 1 3

Related

SQL Query running slow on the DB server

Execution plan is attached
SELECT a.*, k.UserPrivileges, k.Type
FROM NotifyInterests2 a, KUAF k
WHERE a.UserID = k.ID
AND EXISTS (SELECT ID FROM KUAF WHERE a.UserID = ID AND NOT Type IN (1, 2, 4))
AND (a.NodeID IN ( SELECT 0 UNION ALL ( SELECT DISTINCT( -1 * ID )
FROM KUAF WHERE Type = 5 ) UNION ALL ( SELECT DISTINCT AncestorID
FROM DTreeAncestors
WHERE Exists ( SELECT EventInt2 FROM LLEventQueue
WHERE EventHandlerID = 9001 AND EventSeqNo <=45075882 AND EventInt2 = DataID
UNION ALL SELECT EventInt2 * -1 FROM LLEventQueue
WHERE EventHandlerID = 9001
AND EventSeqNo <=45075882 AND EventInt2 = DataID ))))
that's quite the query =) Tip: try to 'group' the parts of your code for readability; it will make your life a 100 times easier; now while you're writing this and even more in the future when you're maintaining this =)
Some questions remain:
What do you call 'slow'?
How many records are present in each table?
How many records are returned by the query?
What are the indexes on the tables? (sp_helpindex)
Also, it probably would have been helpful to see the entire query plan, but one thing that stands out immediately is that KEAF doesn't seem to have clustered index. I presume it's thus also missing a Primary Key? As you have a field ID there I'd expect that this uniquely identifies each record? If so, add a PK to the table and check what effect this has on the entire query.
I've tried to re-arrange things a bit for readability and I ended up with below. I've gambled on some of the aliases as they are missing in the original query.
SELECT a.*, k.UserPrivileges, k.Type
FROM NotifyInterests2 a
JOIN KUAF k
ON k.ID = a.UserID
WHERE EXISTS ( SELECT kx.ID
FROM KUAF kx
WHERE kx.ID = a.UserID
AND NOT kx.Type IN (1, 2, 4) )
AND a.NodeID IN ( SELECT 0
UNION ALL
SELECT DISTINCT( -1 * k5.ID )
FROM KUAF k5
WHERE k5.Type = 5
UNION ALL
SELECT DISTINCT da.AncestorID
FROM DTreeAncestors da
WHERE EXISTS ( SELECT l1.EventInt2
FROM LLEventQueue l1
WHERE l1.EventHandlerID = 9001
AND l1.EventSeqNo <= 45075882
AND l1.EventInt2 = da.DataID
UNION ALL
SELECT l2.EventInt2 * -1
FROM LLEventQueue l2
WHERE l2.EventHandlerID = 9001
AND l2.EventSeqNo <= 45075882
AND l2.EventInt2 = da.DataID )
)
Some parts can be simplified I think.
This doesn't really make sense:
SELECT DISTINCT da.AncestorID
FROM DTreeAncestors da
WHERE EXISTS ( SELECT l1.EventInt2
FROM LLEventQueue l1
WHERE l1.EventHandlerID = 9001
AND l1.EventSeqNo <= 45075882
AND l1.EventInt2 = da.DataID
UNION ALL
SELECT l2.EventInt2 * -1
FROM LLEventQueue l2
WHERE l2.EventHandlerID = 9001
AND l2.EventSeqNo <= 45075882
AND l2.EventInt2 = da.DataID )
You're simply doing the same query twice in the WHERE EXISTS() part.
Also, as this part belongs to a WHERE IN (...) construction there's no real need for the DISTINCT. In fact, it's probably easier to convert it to a WHERE EXISTS() construction. Something like this:
AND ( a.NodeID = 0
OR EXISTS (SELECT *
FROM KUAF k5
WHERE k5.Type = 5
AND ( -1 * k5.ID ) = a.node_id)
OR EXISTS ( SELECT *
FROM DTreeAncestors da
WHERE da.AncestorID = a.NodeID
AND EXISTS ( SELECT *
FROM LLEventQueue l1
WHERE l1.EventHandlerID = 9001
AND l1.EventSeqNo <= 45075882
AND l1.EventInt2 = da.DataID )
)
Normally I'm no fan of OR but I think that in this case it might work.
So I end up with:
SELECT a.*, k.UserPrivileges, k.Type
FROM NotifyInterests2 a
JOIN KUAF k
ON k.ID = a.UserID
WHERE EXISTS ( SELECT kx.ID
FROM KUAF kx
WHERE a.UserID = kx.ID
AND NOT kx.Type IN (1, 2, 4) )
AND ( a.NodeID = 0
OR EXISTS (SELECT *
FROM KUAF k5
WHERE k5.Type = 5
AND ( -1 * k5.ID ) = a.node_id)
OR EXISTS ( SELECT *
FROM DTreeAncestors da
WHERE da.AncestorID = a.NodeID
AND EXISTS ( SELECT *
FROM LLEventQueue l
WHERE l.EventHandlerID = 9001
AND l.EventSeqNo <= 45075882
AND l.EventInt2 = da.DataID )
)
)
Give this a try and check the query plan. If it still is too slow we'll need to look at the indexes that are on the bespoken tables to see where we can optimize those.
You didn't mention if and which indexes exist in the table.
I would try creating the following indexes and see if there is any performance gain:
CREATE INDEX kuaf_idx_id_type ON KUAF (ID,Type);
CREATE INDEX kuaf_idx_type ON KUAF (Type);
CREATE INDEX lleventqueue_idx_eventha_eventin_dataid_eventse ON LLEventQueue (EventHandlerID,EventInt2,DataID,EventSeqNo);

SQL - Finding Gaps in Coverage

I am running this problem on SQL server
Here is my problem.
have something like this
Dataset A
FK_ID StartDate EndDate Type
1 10/1/2018 11/30/2018 M
1 12/1/2018 2/28/2019 N
1 3/1/2019 10/31/2019 M
I have a second data source I have no control over with data something like this:
Dataset B
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/15/2018 M
1 10/1/2018 10/25/2018 M
1 2/15/2019 4/30/2019 M
1 5/1/2019 10/31/2019 M
What I am trying to accomplish is to check to make sure every date within each TYPE M record in Dataset A has at least 1 record in Dataset B.
For example record 1 in Dataset A does NOT have coverage from 10/26/2018 through 11/30/2018. I really only care about when the coverage ends, in this case I want to return 10/26/2018 because it is the first date where the span has no coverage from Dataset B.
I've written a function that does this but it is pretty slow because it is cycling through each date within each M record and counting the number of records in Dataset B. It exits the loop when it finds the first one but I would really like to make this more efficient. I am sure I am not thinking about this properly so any suggestions anyone can offer would be helpful.
This is the section of code I'm currently running
else if #SpanType = 'M'
begin
set #CurrDate = #SpanStart
set #UncovDays = 0
while #CurrDate <= #SpanEnd
Begin
if (SELECT count(*)
FROM eligiblecoverage ec join eligibilityplan ep on ec.plandescription = ep.planname
WHERE ec.masterindividualid = #IndID
and ec.planbegindate <= #CurrDate and ec.planenddate >= #CurrDate
and ec.sourcecreateddate = #MaxDate
and ep.medicaidcoverage = 1) = 0
begin
SET #Result = concat('NON Starting ',format(#currdate, 'M/d/yyyy'))
BREAK
end
set #CurrDate = #CurrDate + 1
end
end
I am not married to having a function it just could not find a way to do this in queries that wasn't very very slow.
EDIT: Dataset B will never have any TYPEs except M so that is not a consideration
EDIT 2: The code offered by DonPablo does de-overlap the data but only in cases where there is an overlap at all. It reduces dataset B to:
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/25/2018 M
instead of
FK_ID SpanStart SpanEnd Type
1 10/1/2018 10/25/2018 M
1 2/15/2019 4/30/2019 M
1 5/1/2019 10/31/2019 M
I am still futzing around with it but it's a start.
I would approach this by focusing on B. My assumption is that any absent record would follow span_end in the table. So here is the idea:
Unpivot the dates in B (adding "1" to the end dates)
Add a flag if they are present with type "M".
Check to see if any not-present records are in the span for A.
Check the first and last dates as well.
So, this looks like:
with bdates as (
select v.dte,
(case when exists (select 1
from b b2
where v.dte between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 1 else 0
end) as in_b
from b cross apply
(values (spanstart), (dateadd(day, 1, spanend)
) v(dte)
where b.type = 'M' -- all we care about
group by v.dte -- no need for duplicates
)
select a.*,
(case when not exists (select 1
from b b2
where a.startdate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 0
when not exists (select 1
from b b2
where a.enddate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
when exists (select 1
from bdates bd
where bd.dte between a.startdate and a.enddate and
bd.in_b = 0
)
then 0
when exists (select 1
from b b2
where a.startdate between b2.spanstart and b2.spanend and
b2.type = 'M'
)
then 1
else 0
end)
from a;
What is this doing? Four validity checks:
Is the starttime valid?
Is the endtime valid?
Are any intermediate dates invalid?
Is there at least one valid record?
Start by framing the problem in smaller pieces, in a sequence of actions like I did in the comment.
See George Polya "How To Solve It" 1945
Then Google is your friend -- look at==> sql de-overlap date ranges into one record (over a million results)
UPDATED--I picked Merge overlapping dates in SQL Server
and updated it for our table and column names.
Also look at theory from 1983 Allen's Interval Algebra https://www.ics.uci.edu/~alspaugh/cls/shr/allen.html
Or from 2014 https://stewashton.wordpress.com/2014/03/11/sql-for-date-ranges-gaps-and-overlaps/
This is a primer on how to setup test data for this problem.
Finally determine what counts via Ranking the various pairs of A vs B --
bypass those totally Within, then work with earliest PartialOverlaps, lastly do the Precede/Follow items.
--from Merge overlapping dates in SQL Server
with SpanStarts as
(
select distinct FK_ID, SpanStart
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanStart < t1.SpanStart
and t2.SpanEnd >= t1.SpanStart)
),
SpanEnds as
(
select distinct FK_ID, SpanEnd
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanEnd > t1.SpanEnd
and t2.SpanStart <= t1.SpanEnd)
),
DeOverlapped_B as
(
Select FK_ID, SpanStart,
(select min(SpanEnd) from SpanEnds as e
where e.FK_ID = s.FK_ID
and SpanEnd >= SpanStart) as SpanEnd
from SpanStarts as s
)
Select * from DeOverlapped_B
Now we have something to feed into the next steps, and we can use the above as a CTE
======================================
with SpanStarts as
(
select distinct FK_ID, SpanStart
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanStart < t1.SpanStart
and t2.SpanEnd >= t1.SpanStart)
),
SpanEnds as
(
select distinct FK_ID, SpanEnd
from Coverage_B as t1
where not exists
(select * from Coverage_B as t2
where t2.FK_ID = t1.FK_ID
and t2.SpanEnd > t1.SpanEnd
and t2.SpanStart <= t1.SpanEnd)
),
DeOverlapped_B as
(
Select FK_ID, SpanStart,
(select min(SpanEnd) from SpanEnds as e
where e.FK_ID = s.FK_ID
and SpanEnd >= SpanStart) as SpanEnd
from SpanStarts as s
),
-- find A row's coverage
ACoverage as (
Select
a.*, b.SpanEnd, b.SpanStart,
Case
When SpanStart <= StartDate And StartDate <= SpanEnd
And SpanStart <= EndDate And EndDate <= SpanEnd
Then '1within' -- starts, equals, during, finishes
When EndDate < SpanStart
Or SpanEnd < StartDate
Then '3beforeAfter' -- preceeds, meets, preceeded, met
Else '2overlap' -- one or two ends hang over spanStart/End
End as relation
From Coverage_A a
Left Join DeOverlapped_B b
On a.FK_ID = b.FK_ID
Where a.Type = 'M'
)
Select
*
,Case
When relation1 = '2' And StartDate < SpanStart Then StartDate
When relation1 = '2' Then DateAdd(d, 1, SpanEnd)
When relation1 = '3' Then StartDate
End as UnCoveredBeginning
From (
Select
*
,SUBSTRING(relation,1,1) as relation1
,ROW_NUMBER() Over (Partition by A_ID Order by relation, SpanStart) as Rownum
from ACoverage
) aRNO
Where Rownum = 1
And relation1 <> '1'

In plpgsql (of PostgreSQL), can a CTE be preserved to an outer loop?

(Edited from the original).
In plpgsql, (PostgreSQL 9.2), I have a function defined as:
CREATE OR REPLACE FUNCTION test (patient_recid integer, tencounter timestamp without time zone)
RETURNS SETOF view_dx AS
$BODY$
#variable_conflict use_column
DECLARE
r view_dx%rowtype;
BEGIN
FOR r IN
With person AS (
select ....
)
, alldx AS (
select ....
)
............
select ... from first cte
union
select ... from second cte
union
etc., etc.,
LOOP
r.tposted = ( .
With person AS (
... SAME AS ABOVE,
alldx AS (
... SAME AS ABOVE,
)
select max(b.tposted)
from alldx b
where r.cicd9 = b.code and r.cdesc = b.cdesc);
r.treated = (
With person AS (
........SAME AS ABOVE )
, alldx AS (
........SAME AS ABOVE
)
select ...);
r.resolved = (
With person AS (
select p.chart_recid as recid
from patients p
where p.recid = patient_recid
)
...etc, etc,
RETURN NEXT r;
END LOOP;
RETURN;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION test(integer, timestamp without time zone)
OWNER TO postgres;
Edit: Essentially, I have multiple cte's defined which work well in the "For r IN" section of code with multiple unions, but when executing the LOOP...END LOOP section, each CTE needs to be redefined with each SELECT statement. Is there a good way to avoid multiple definitions of the same CTE?
Or is there a better (i.e., faster) way of doing this.
All suggestions are most welcome and appreciated.
TIA
[this is not an answer (too little information, too large program), but a hint for rewriting the stacked CTE.]
The members of the union all appear to be based on select b.* from alldx b, all with a few different extra conditions, mostly based on the existance of other tuples within the same CTE. My suggestion is to unify these, replacing them by boolean flags, as in:
WITH person AS (
SELECT p.chart_recid as recid
FROM patients p
WHERE p.recid = patient_recid
)
, alldx AS (
SELECT d.tposted, d.treated, d.resolved, d.recid as dx_recid, d.pmh, d.icd9_recid
, i.code, i.cdesc, i.chronic
FROM dx d
JOIN icd9 i ON d.icd9_recid = i.recid
JOIN person p ON d.chart_recid = p.recid
WHERE d.tposted::date <= tencounter::date
)
SELECT uni.tposted, uni.treated, uni.resolved, uni.dx_recid, uni.pmh, uni.icd9_recid
, uni.code, uni.cdesc, uni.chronic
, (uni.tposted::date = tencounter::date
) AS is_dx_at_encounter -- bitfield
, EXISTS ( -- a record from a more recent date has resolved this problem.
SELECT 1
FROM alldx x
WHERE x.resolved = true
AND uni.code = x.code AND uni.cdesc = x.cdesc AND uni.tposted = x.tposted
AND x.tposted >= uni.tposted
) AS dx_resolved -- bitfield
, EXISTS ( -- a record from a more recent date has resolved this problem.
SELECT 1
FROM alldx x
WHERE x.resolved = false
AND uni.code = x.code AND uni.cdesc = x.cdesc AND uni.tposted = x.tposted
AND x.tposted > uni.tposted
) AS dx_recurred -- bitfield
, EXISTS ( SELECT * from alldx x where x.chronic = true
AND uni.code = x.code AND uni.cdesc = x.cdesc
) AS dx_chronic -- bitfield
-- etcetera
FROM alldx uni
;
The person CTE could probably be incorporated, too.
and maybe you don't even need the final loop
but you'll have to find out which combination(s) of the resulting bitfields will be needed.
the UNION (without ALL) in the original is a terrible beast: it collects all the results from the union parts, but has to remove duplicates. This will probably introduce a sort-step, since CTE-references tend to hide their key fields or implied ordering from the calling query.
As far as I can tell, CTE's defined before the LOOP do not transfer to the LOOP itself. However, a temporary table can be defined in the BEGIN block which is available in the LOOP block. The following solution runs 50 times faster then my original code. Anybody have a better approach?
CREATE OR REPLACE FUNCTION test2 (patient_recid integer, tencounter timestamp without time zone)
RETURNS SETOF view_dx AS
$BODY$
#variable_conflict use_column
DECLARE
r view_dx%rowtype;
BEGIN
-- create table can only be created in the BEGIN block
Create temp table all_dx ON COMMIT DROP AS
With person AS (
select p.chart_recid as recid
from patients p
where p.recid = patient_recid
)
, alldx AS (
select d.tposted, d.treated, d.resolved, d.recid as dx_recid, d.pmh, d.icd9_recid, i.code, i.cdesc, i.chronic
from dx d
join icd9 i on (d.icd9_recid = i.recid)
join person p on (d.chart_recid = p.recid)
where d.tposted::date <= tencounter::date
)
select * from alldx order by tposted desc;
-- will loop through all the records produced by the unions and assign tposted, pmh, chronic, etc...
FOR r IN
With
dx_at_encounter AS ( -- get all diagnosis at time of encounter
select code, cdesc from all_dx a
where a.tposted::date = tencounter::date
)
, dx_resolved AS ( -- get most recent date of every resolved problem.
select b.* from all_dx b
join (
select a.code, a.cdesc , max(tposted) as tposted
from all_dx a
where a.resolved = true
group by code,cdesc) j
on (b.code = j.code and b.cdesc = j.cdesc and b.tposted = j.tposted)
)
, never_resolved AS ( -- get all problems that have never been resolved before time of encounter.
-- "not exists" is applied to each select output row AFTER the output row b.* is formed.
select b.code, b.cdesc from all_dx b
where not exists
(select 1
from dx_resolved d
where b.code = d.code and b.cdesc = d.cdesc)
)
, recurrent AS ( -- get all recurrent problems. (Problems that are now current after being resolved).
select b.code, b.cdesc
from all_dx b
join dx_resolved r on (b.cdesc = r.cdesc and b.tposted::date > r.tposted::date )
where (b.resolved is null or b.resolved = false)
)
, chronic_dx AS (
select b.code, b.cdesc
from all_dx b
where b.chronic = true
)
-- all diagnosis at time of encounter
select a.code,
a.cdesc
from dx_at_encounter a
union
-- all recurrent problems
select
a.code,
a.cdesc
from recurrent a
union
-- all problems that have never been resolved
select
a.code,
a.cdesc
from never_resolved a
union
--all chonic problems
select
a.code,
a.cdesc
from chronic_dx a
-- LOOP goes to END LOOP which returns back to LOOP to process each of the result records from the unions.
LOOP
r.tposted = ( -- get most recent useage of a diagnosis.
select max(b.tposted)
from all_dx b
where r.cicd9 = b.code and r.cdesc = b.cdesc);
r.treated = (
select b.treated from all_dx b
where b.tposted = r.tposted and b.code = r.cicd9 and b.cdesc = r.cdesc);
r.resolved = (
select b.resolved from all_dx b
where b.tposted = r.tposted and b.code = r.cicd9 and b.cdesc = r.cdesc);
r.pmh = (
select distinct true
from all_dx b
where
b.pmh = true and
b.code = r.cicd9 and
b.cdesc = r.cdesc );
r.chronic = (
select distinct true
from all_dx b
where
b.chronic = true and
b.code = r.cicd9 and
b.cdesc = r.cdesc);
RETURN NEXT r; -- return current row of SELECT
END LOOP;
RETURN;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
ALTER FUNCTION test2(integer, timestamp without time zone)
OWNER TO postgres;

Get minimum value greater than zero

I have the following table:
column1 column2 column3
3 2 0
5 9 2
1 4 6
When I run the following code:
SELECT
id_function = #param,
MIN(t1.column1) AS c1min,
MAX(t1.column2) AS c2max,
MIN(t1.column3) AS c3min
FROM
table1 (NOLOCK) AS t1
WHERE
t1.id = #param
I get:
c1min c2max c3min
1 9 0
My problem is that c3min must be the minimum value greater than zero.
The result I need should be:
c1min c2max c3min
1 9 2
Is there any way to do that without using a subselect?
Any help will be appreciated.
Thank you!
I would recommend using nullif() so your query would be
SELECT id_function = #param,
MIN(t1.column1) AS c1min,
MAX(t1.column2) AS c2max,
MIN(NULLIF(t1.column3,0) AS c3min
FROM table1 (NOLOCK) AS t1
WHERE t1.id = #param
that way you don't risk altering your results, e.g. if your real minimum in column 3 is 100 the previous answer would affect your results, and also if you only have zeros in your column 3 column the previous answer would also deliver incorrect results
You could use a case to set the 0 value to a higher value on your min() condition
SELECT id_function = #param,
MIN(t1.column1) AS c1min,
MAX(t1.column2) AS c2max,
MIN(case when t1.column3 = 0 then 99 else t1.column3 end) AS c3min
FROM table1 (NOLOCK) AS t1
WHERE t1.id = #param
It work .
(But I thing answer of :Hedinn is best answer ).
SELECT id_function = #param ,
c1min = ( SELECT MIN(t1Sub.column1)
FROM table1 (NOLOCK) AS t1Sub
WHERE t1Sub.id = #param
) ,
c2max = ( SELECT MAX(t2Sub.column2)
FROM table1 (NOLOCK) AS t2Sub
WHERE t2Sub.id = #param
) ,
c3min = ( SELECT MIN(t3Sub.column3)
FROM table1 (NOLOCK) AS t3Sub
WHERE ( t3Sub.id = #param )
AND ( t3Sub.column3 <> 0 )
)
FROM table1 (NOLOCK) AS t1
WHERE ( t1.id = #param )

how to convert the below subquery into joins using one update statement

Below is a complete query I have and the ultimate aim is to update the claim table. But it should be only one statement without any subquery, only joins are allowed because I am going to run this in an appliance which won't support subquery:
DECLARE #DecWdrwn as TABLE(CtryId smallint, CmId int, DecWdrwnDt int);
WITH s AS
(
SELECT
Ctryid,CmId,Dt,
ISNULL((
SELECT max(CmHistDtTmId)
FROM ClaimHistory l
WHERE St = 3
AND l.Ctryid = c.Ctryid
AND l.CmId = c.CmId)
, 0) MaxDec,
ISNULL((
SELECT max(CmHistDtTmId)
FROM ClaimHistory l
WHERE St = 7
AND l.Ctryid = c.Ctryid
AND l.CmId = c.CmId)
, 0) MaxSet
FROM
ClaimHistory c
WHERE
St =3
)
INSERT INTO #DecWdrwn
SELECT CtryId, CmId, Max(Dt) DecDt
FROM s
WHERE MaxSet > MaxDec
GROUP BY CtryId,CmId
Your response is much appreciated...
UPDATE Claims
SET CmDclnWdwnDt = (
SELECT DecWdrwnDt
FROM #DecWdrwn d
WHERE d.CmId = Claims.CmId
AND d.CtryId = Claims.CtryId
)
WHERE EXISTS (
SELECT *
FROM #DecWdrwn d
WHERE d.CmId = Claims.CmId
AND d.CtryId = Claims.CtryId
)
Please try INNER JOIN Update:
UPDATE a
SET a.CmDclnWdwnDt = b.DecWdrwnDt
FROM Claims a, #DecWdrwn b
WHERE a.CmId = b.CmId AND
a.CtryId =b.CtryId

Resources