tsql where clause find a value from subquery's top 1 value - tsql

We have a slow query something like this:
select id
from task t
inner join TaskLog tl
on t.id = tl.id
where tl.PostImage =
(
select top 1 tll.PostImage
from TaskLog tll
where tll.id = t.id
)
group by t1.PostImage, t.id
It looked like the tl.PostImage = (subquery) caused the slowness. How do I rewrite this to make it run faster?
EDIT:
I have simplified the question in an incorrect way. Because of this the solution was not helped me. Here is the actual query I had:
SELECT distinct(p.Task_id), 1 as TotalReferrals
FROM Task p inner join Task_Log PL on PL.Task_ID = P.Task_ID
where (MONTH(P.CreateDate) = #Month
AND YEAR(P.CreateDate) = #Year)
and (((p.Worker like 'k3%'
and p.CreateDate < '12/6/2010')
or (p.Worker in ('k22', 'k27', 'k29')
and p.CreateDate >= '12/6/2010' and p.ModifiedDate < '12/1/2013')
or (p.Worker in ('K4A', 'K46', 'K48')
and p.CreateDate >= '12/1/2013'))
or (pl.post_image = (select top 1 pll.post_image
from Task_log pll
where pll.Task_id = p.Task_id
and pll.pre_image = 'Unknown'
and pll.changed_column_nm = 'Worker'
and (Month(pll.CreateDate) = #Month
and Year(pll.CreateDate) = #Year)
and ((pll.post_image like 'k3%'
and pll.CreateDate < '12/6/2010')
or (pll.post_image in ('k22', 'k27', 'k29')
and pll.CreateDate >= '12/6/2010' and pll.CreateDate < '12/1/2013')
or (pll.post_image in ('K4A', 'K46', 'K48')
and pll.CreateDate >= '12/1/2013'))
group by pll.post_image, pll.log_id
)
))
group by pl.post_image, p.Task_id, pl.CreateDate

SELECT Min(T.id)
FROM Task T
INNER JOIN TaskLog TL
ON T.id = TL.id
GROUP BY TL.PostImage

You might try to erase the subselect:
SELECT Distinct(P.Task_id), 1 as TotalReferrals
FROM Task P
INNER JOIN
Task_Log PL
ON PL.Task_ID = P.Task_ID
WHERE (MONTH(P.CreateDate) = #Month
AND YEAR(P.CreateDate) = #Year)
AND (((P.Worker like 'k3%'
AND P.CreateDate < '12/6/2010')
OR (P.Worker in ('k22', 'k27', 'k29')
AND P.CreateDate >= '12/6/2010' and P.ModifiedDate < '12/1/2013')
OR (P.Worker in ('K4A', 'K46', 'K48')
AND P.CreateDate >= '12/1/2013'))
OR (PL.pre_image = 'Unknown'
AND PL.changed_column_nm = 'Worker'
AND Month(PL.CreateDate) = #Month
AND Year(PL.CreateDate) = #Year
AND (PL.post_image like 'k3%'
AND PL.CreateDate < '12/6/2010')
OR (PL.post_image in ('k22', 'k27', 'k29')
AND PL.CreateDate >= '12/6/2010'
AND PL.CreateDate < '12/1/2013')
OR (PL.post_image in ('K4A', 'K46', 'K48')
AND PL.CreateDate >= '12/1/2013'))
GROUP BY PL.post_image, P.Task_id, PL.CreateDate

Related

How to append CTE results to main query output?

I've created a TSQL query that pulls from two sets of tables in my database. The tables in the Common Table Expression are different from the tables in the main query. I'm joining on MRN and need the end result to contain accounts from both sets of tables. I've written the following query to this end:
with cteHosp as(
select Distinct p.EncounterNumber, p.MRN, p.AdmitAge
from HospitalPatients p
inner join Eligibility e on p.MRN = e.MRN
inner join HospChgDtl c on p.pt_id = c.pt_id
inner join HospitalDiagnoses d on p.pt_id = d.pt_id
where p.AdmitAge >=12
and d.dx_cd in ('G89.4','R52.1','R52.2','Z00.129')
)
Select Distinct a.AccountNo, a.dob, DATEDIFF(yy, a.dob, GETDATE()) as Age
from RHCCPTDetail c
inner join RHCAppointments a on c.ClaimID = a.ClaimID
inner join Eligibility e on c.hl7Id = e.MRN
full outer join cteHosp on e.MRN = cteHosp.MRN
where DATEDIFF(yy, a.dob, getdate()) >= 12
and left(c.PriDiag,7) in ('G89.4','R52.1','R52.2', 'Z00.129')
or (
DATEDIFF(yy, a.dob, getdate()) >= 12
and LEFT(c.DiagCode2,7) in ('G89.4','R52.1','R52.2','Z00.129')
)
or (
DATEDIFF(yy, a.dob, getdate()) >= 12
and LEFT(c.DiagCode3,7) in ('G89.4','R52.1','R52.2','Z00.129')
)
or (
DATEDIFF(yy, a.dob, getdate()) >= 12
and LEFT(c.DiagCode4,7) in ('G89.4','R52.1','R52.2','Z00.129')
)
order by AccountNo
How do I merge together the output of both the common table expression and the main query into one set of results?
Merge performs inserts, updates or deletes. I believe you want to join the cte. If so, here is an example.
Notice the cteBatch is joined to the Main query below.
with
cteBatch (BatchID,BatchDate,Creator,LogID)
as
(
select
BatchID
,dateadd(day,right(BatchID,3) -1,
cast(cast(left(BatchID,4) as varchar(4))
+ '-01-01' as date)) BatchDate
,Creator
,LogID
from tblPriceMatrixBatch b
unpivot
(
LogID
for Logs in (LogIDISI,LogIDTG,LogIDWeb)
)u
)
Select
0 as isCurrent
,i.InterfaceID
,i.InterfaceName
,b.BatchID
,b.BatchDate
,case when isdate(l.start) = 0 and isdate(l.[end]) = 0 then 'Scheduled'
when isdate(l.start) = 1 and isdate(l.[end]) = 0 then 'Running'
when isdate(l.start) = 1 and isdate(l.[end]) = 1 and isnull(l.haserror,0) = 1 then 'Failed'
when isdate(l.start) = 1 and isdate(l.[end]) = 1 and isnull(l.haserror,0) != 1 then 'Success'
else 'idunno' end as stat
,l.Start as StartTime
,l.[end] as CompleteTime
,b.Creator as Usr
from EOCSupport.dbo.Interfaces i
join EOCSupport.dbo.Logs l
on i.InterfaceID = l.InterfaceID
join cteBatch b
on b.logid = l.LogID

Find matching records in same table different columns

I have this query:
SELECT
TLOCMTR.LOCATN_K, TLOCMTR.MTR_SRP_N, TLOCMTR.MTR_INST_D,
TLOCMTR.MTR_XCHG_OUT_D, RATE.RATE, TMTR.MTR_MFR_MOD_C,
TMTR.MTR_MFR_NM_CD
FROM
TMTR
RIGHT OUTER JOIN
TLOCMTR ON TMTR.MTR_SRP_N = TLOCMTR.MTR_SRP_N
LEFT OUTER JOIN
RATE ON TLOCMTR.LOCATN_K = RATE.LOCATN_K
WHERE
((RATE.RATE >= 20) AND (RATE.RATE <= 29))
AND TLOCMTR.MTR_INST_D >= '2014-01-01'
ORDER BY
LOCATN_K, MTR_INST_D
The code results in:
What I need to do is count the number of times the MTR_MFR_NM_CD changes from AMP to <>AMP per Locatn_K where the MTR_INST_D = MTR_XCHG_OUT_D. For example LOCATN_K = 85420005 went from AMP to EEM and the MTR_XCHG_D = MTR_INST_D 1 time (date was '2014-08-27'. LOCATN_K 85430001 went from AMP to EEM 2 times on dates '2015-01-05' and '2016-01-12.
Please help me with some T-SQL to answer this!
this is the essentials
select *
from ( select LOCATN_K, MTR_INST_D, MTR_MFR_NM_CD
, LEAD(MTR_MFR_NM_CD, 1,0) OVER (PARTITTION LOCATN_K BY ORDER BY MTR_INST_D) AS MTR_MFR_NM_CD_NEXT
from
...
) tt
where MTR_MFR_NM_CD = 'AMP'
and MTR_MFR_NM_CD_NEXT <> 'AMP'
I tried Frisbee's code with the following modifications but did not get the exact results:
select *
from ( select TLOCMTR.LOCATN_K, TLOCMTR.MTR_SRP_N, TLOCMTR.MTR_INST_D, TLOCMTR.MTR_XCHG_OUT_D, TMTR.MTR_MFR_MOD_C, TMTR.MTR_MFR_NM_CD,
LEAD(TMTR.MTR_MFR_NM_CD, 1,0) OVER (PARTITION BY TLOCMTR.LOCATN_K
ORDER BY MTR_INST_D) AS MTR_MFR_NM_CD_NEXT
FROM TMTR RIGHT OUTER JOIN TLOCMTR ON TMTR.MTR_SRP_N = TLOCMTR.MTR_SRP_N
LEFT OUTER JOIN RATE ON TLOCMTR.LOCATN_K = RATE.LOCATN_K
WHERE ((RATE.RATE >= 20) AND (RATE.RATE <= 29)) AND TLOCMTR.MTR_INST_D>='2014-01-01' AND TMTR.MTR_MFR_NM_CD = 'AMP'
) tt
where tt.MTR_MFR_NM_CD = 'AMP'
and tt.MTR_MFR_NM_CD_NEXT <> 'AMP'
order by tt.LOCATN_K
This resulted in getting 'Amp' to 'Amp' and <>'Amp' to 'Amp', but what I just wanted to get was 'Amp'to <>'Amp'.
The easiest way for me to do this was:
WITH A AS
(SELECT TLOCMTR.LOCATN_K, TLOCMTR.MTR_SRP_N, TLOCMTR.MTR_XCHG_OUT_D, TMTR.MTR_MFR_MOD_C, TMTR.MTR_MFR_NM_CD
FROM TMTR RIGHT OUTER JOIN TLOCMTR ON TMTR.MTR_SRP_N = TLOCMTR.MTR_SRP_N LEFT OUTER JOIN RATE ON TLOCMTR.LOCATN_K = RATE.LOCATN_K
WHERE ((RATE.RATE >= 20) AND (RATE.RATE <= 29)) and TLOCMTR.MTR_INST_D>='2014-01-01' AND TMTR.MTR_MFR_NM_CD = 'AMP'
),
B AS(
SELECT TLOCMTR.LOCATN_K, TLOCMTR.MTR_SRP_N, TLOCMTR.MTR_INST_D, TMTR.MTR_MFR_MOD_C, TMTR.MTR_MFR_NM_CD
FROM TMTR RIGHT OUTER JOIN TLOCMTR ON TMTR.MTR_SRP_N = TLOCMTR.MTR_SRP_N
LEFT OUTER JOIN RATE ON TLOCMTR.LOCATN_K = RATE.LOCATN_K
WHERE ((RATE.RATE >= 20) AND (RATE.RATE <= 29)) AND TLOCMTR.MTR_INST_D>='2014-01-01' AND TMTR.MTR_MFR_NM_CD <> 'AMP'
)
SELECT A.LOCATN_K, A.MTR_SRP_N AmpyMeter, B.MTR_SRP_N CreditMeter, B.MTR_INST_D EXCG_DT, A.MTR_MFR_MOD_C AMP_MODEL, B.MTR_MFR_MOD_C Credit_MODEL
FROM A inner join B on A.MTR_XCHG_OUT_D = B.MTR_INST_D and A.LOCATN_K=B.LOCATN_K
ORDER BY LOCATN_K
My final results look like:

How do I get the max from a partitioned query using Rank ()

I want the result to return the max Rank when partitioned using the rank function.
I am using the following query.
SELECT DISTINCT dbo.pomst.co_num
,dbo.pomst.wh_num
,dbo.pomst.po_number
,dbo.pomst.po_suffix
,dbo.pomst.vendor_id
,dbo.item.uom
,dbo.item.upc_num
,dbo.item.item_desc
,RIGHT(dbo.auditlog.pallet_id, 8) AS pallet_id
,dbo.auditlog.abs_num
,dbo.auditlog.item_qty
,dbo.auditlog.lot
,dbo.auditlog.packer
,auditlog.comments
,auditlog.date_time
,rank() OVER (
PARTITION BY auditlog.comments ORDER BY auditlog.date_time ASC
) AS CorrectTrans
FROM dbo.auditlog
INNER JOIN dbo.pomst ON dbo.auditlog.co_num = dbo.pomst.co_num
AND dbo.auditlog.wh_num = dbo.pomst.wh_num
AND dbo.auditlog.po_number = dbo.pomst.po_number
AND dbo.auditlog.po_suffix = dbo.pomst.po_suffix
INNER JOIN dbo.item ON dbo.auditlog.co_num = dbo.item.co_num
AND dbo.auditlog.wh_num = dbo.item.wh_num
AND dbo.auditlog.abs_num = dbo.item.abs_num
WHERE (dbo.pomst.co_num = 'AC01')
AND (dbo.pomst.wh_num = 'KU22')
AND (dbo.pomst.row_status = 'C')
AND (dbo.auditlog.trans_type = 're')
AND item_qty NOT LIKE '-%'
I figured it out! I was trying to get the max result of a rank, but if I flip order of rank from asc to desc and use a CTE I can select the the results that always have 1 as the rank as opposed to trying to get the Max. I would still like to know how to get the Max rank but this solution suits my needs.
;with cte as
(SELECT DISTINCT dbo.pomst.co_num
,dbo.pomst.wh_num
,dbo.pomst.po_number
,dbo.pomst.po_suffix
,dbo.pomst.vendor_id
,dbo.item.uom
,dbo.item.upc_num
,dbo.item.item_desc
,RIGHT(dbo.auditlog.pallet_id, 8) AS pallet_id
,dbo.auditlog.abs_num
,dbo.auditlog.item_qty
,dbo.auditlog.lot
,dbo.auditlog.packer
,auditlog.comments
,auditlog.date_time
,rank() OVER (
PARTITION BY auditlog.comments ORDER BY auditlog.date_time desc
) AS CorrectTrans
FROM dbo.auditlog
INNER JOIN dbo.pomst ON dbo.auditlog.co_num = dbo.pomst.co_num
AND dbo.auditlog.wh_num = dbo.pomst.wh_num
AND dbo.auditlog.po_number = dbo.pomst.po_number
AND dbo.auditlog.po_suffix = dbo.pomst.po_suffix
INNER JOIN dbo.item ON dbo.auditlog.co_num = dbo.item.co_num
AND dbo.auditlog.wh_num = dbo.item.wh_num
AND dbo.auditlog.abs_num = dbo.item.abs_num
WHERE (dbo.pomst.co_num = 'AC01')
AND (dbo.pomst.wh_num = 'KU22')
AND (dbo.pomst.row_status = 'C')
AND (dbo.auditlog.trans_type = 're')
AND item_qty NOT LIKE '-%'
)
Select * from cte
where CorrectTrans = 1
Add select and group by and use your existing query as a sub query.
Try ..
select max([CorrectTrans]), Vendor_Id, Item_qty, Lot, Pallet_id
from (
-- Your existing query --
SELECT DISTINCT dbo.pomst.co_num
,dbo.pomst.wh_num
,dbo.pomst.po_number
,dbo.pomst.po_suffix
,dbo.pomst.vendor_id
,dbo.item.uom
,dbo.item.upc_num
,dbo.item.item_desc
,RIGHT(dbo.auditlog.pallet_id, 8) AS pallet_id
,dbo.auditlog.abs_num
,dbo.auditlog.item_qty
,dbo.auditlog.lot
,dbo.auditlog.packer
,auditlog.comments
,auditlog.date_time
,rank() OVER (
PARTITION BY auditlog.comments ORDER BY auditlog.date_time ASC
) AS CorrectTrans
FROM dbo.auditlog
INNER JOIN dbo.pomst ON dbo.auditlog.co_num = dbo.pomst.co_num
AND dbo.auditlog.wh_num = dbo.pomst.wh_num
AND dbo.auditlog.po_number = dbo.pomst.po_number
AND dbo.auditlog.po_suffix = dbo.pomst.po_suffix
INNER JOIN dbo.item ON dbo.auditlog.co_num = dbo.item.co_num
AND dbo.auditlog.wh_num = dbo.item.wh_num
AND dbo.auditlog.abs_num = dbo.item.abs_num
WHERE (dbo.pomst.co_num = 'AC01')
AND (dbo.pomst.wh_num = 'KU22')
AND (dbo.pomst.row_status = 'C')
AND (dbo.auditlog.trans_type = 're')
AND item_qty NOT LIKE '-%'
-- =======================================
) x
group by Vendor_id, Item_qty, Lot, Pallet_id

Why doesn't work ADate between #Startdate and #Enddate?

I have a query like this:
SELECT #Amount = SUM(T.Amount) FROM (
SELECT
(
SELECT DISTINCT SUM(X.Price)
FROM X
WHERE X.ID = Y.XID OR X.ID = Z.XID
AND (X.ADate BETWEEN #StartDate AND #EndDate)
) AS Amount
FROM B
LEFT JOIN Y ON B.YId = Y.Id
LEFT JOIN Z ON B.ZId = Z.Id
WHERE B.Id = #Id
AND (B.YId = #YId OR #YId < 0)
AND (B.ZId = #ZId OR #ZId < 0)) AS T
And which start and end date I choose. The result is the same.
By example a start date 1/1/2012 and a end date 1/31/2012
and then a selection of a start date 1/1/2014 and a end date 1/31/2014
by the following data: Price 500 and a ADate = 1/24/2012
Both results are 500?!
What do I wrong?
I've tried to:
AND (X.ADate BETWEEN CAST(#StartDate AS DATETIME) AND CAST(#EndDate AS DATETIME))
Sleeping is good. The problem was => ( and ) was missing.
Solvation: WHERE (X.ID = Y.XID OR X.ID = Z.XID)

set value from select for few select

I have select, iside select have 2 column. This column must be filled from same select, but I don't want use select twice for it. Is it possoble use select 1 time and after that set second column value from first?
Example:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = (select aa from table1 where quantity > 5)
I need:
insert into #temptable from
select
a = (select aa from table1 where quantity > 5)
b = {value from a}
Update. I wrote bad example, I need set to BalancePrediction1 and BalancePrediction2 value from Balance
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance -
(
SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
)
) as Balance,
Balance AS 'BalancePrediction1',
Balance AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
You could do an update to the table variable after the insert.
update #tmpBalances
set BalancePrediction1 = Balance,
BalancePrediction2 = Balance
Or you can use cross apply to calculate the sum.
INSERT #tmpBalances
SELECT PA.ContractId AS 'ContractId',
Con.Name AS 'ContractName',
Bal.PortfolioAccountId AS 'PortfolioAccountId',
PA.Name AS 'PortfolioAccountName',
RA.GeneralId AS 'RegisterAccountGeneralId',
Bal.BalanceTypeId AS 'BalanceTypeId',
Bt.Name AS 'BalanceTypeName',
Bt.Type AS 'BalanceTypeType',
Bal.BalanceTimeType AS 'BalanceTimeType',
Bal.InstrumentId AS 'InstrumentId',
Ins.Name AS 'InstrumentName',
Ins.GeneralId AS 'InstrumentGeneralId',
(Bal.Balance - Mov.SumAmount) AS Balance,
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction1',
(Bal.Balance - Mov.SumAmount) AS 'BalancePrediction2',
Bal.CurrencyId AS 'CurrencyId',
Ccy.Code AS 'CurrencyCode',
PA.PositionServiceType 'PositionServiceType',
Ccy.Name 'CurrencyName',
S.Nominal AS 'Nominal',
S.NominalCurrencyId AS 'NominalCurrencyId',
trd.GetCurrencyCode(S.NominalCurrencyId) AS 'NominalCurrencyCode'
FROM trd.Balances AS Bal
JOIN trd.PortfolioAccounts AS PA ON PA.Id = Bal.PortfolioAccountId
JOIN trd.Contracts AS Con ON Con.Id = PA.ContractId
JOIN trd.RegisterAccounts AS RA ON RA.Id = PA.RegisterAccountId
JOIN trd.BalanceTypes AS Bt ON Bt.Id = Bal.BalanceTypeId
JOIN trd.Instruments AS Ins ON Ins.Id = Bal.InstrumentId
LEFT OUTER JOIN trd.Currencies AS Ccy ON Ccy.Id = Bal.CurrencyId
LEFT JOIN trd.SecuritiesView S ON s.Id = Ins.Id AND DateDiff(d, S.ValidFrom, #Date) >= 0 AND (S.ValidTo IS NULL OR DateDiff(d, S.ValidTo, #Date) < 0)
AND S.InstrumentInstrumentTypePriceUnit = 1
CROSS APPLY (SELECT COALESCE(SUM(Mov.Amount), 0)
FROM trd.Movements AS Mov
WHERE
Bal.InstrumentId = Mov.InstrumentId AND
Bal.PortfolioAccountId = Mov.PortfolioAccountId AND
Bal.BalanceTypeId = Mov.BalanceTypeId AND
Bal.BalanceTimeType = Mov.BalanceTimeType AND
DateDiff(DAY, #Date, Mov.Date) > 0 AND
-- Currency může být null a NULL = NULL nejde
COALESCE(Bal.CurrencyId, -1) = COALESCE(Mov.CurrencyId, -1)
) Mov(SumAmount)
SELECT aa AS a, aa AS b
FROM table1
WHERE quantity > 5
One way;
;with T (value) as (
select aa from table1 where quantity > 5
)
insert into #temptable
select value, value from T