SQL Server recursive query using MIN() - sql

I'm trying to use MIN() function in my query to get minimum date from lower level of the tree nodes upward and check the date recursively but can't figure out how to do it using the MIN function.
So far I have written this query to get tree hierarchy:
WITH cteP AS
(
SELECT
WBS, WBSParent,
StartActual,
HierID = CONVERT(hierarchyid, CONCAT('/', WBS, '/'))
FROM
MSP.MSPMAIN
WHERE
ISNULL(#Top,-1) = CASE
WHEN #Top IS NULL
THEN ISNULL(WBSParent, -1)
ELSE WBS
END
UNION ALL
SELECT
WBS = r.WBS,
WBSParent = r.WBSParent,
StartActual = r.StartActual,
HierID = CONVERT(hierarchyid, CONCAT(p.HierID.ToString(), r.WBS, '/'))
FROM
MSP.MSPMAIN r
JOIN
cteP p ON r.WBSParent = p.WBS
)
SELECT
Lvl = HierID.GetLevel(),
WBS, WBSParent,
StartActual
FROM
cteP A
ORDER BY
A.HierID
Sample data
insert into MSPMAIN (WBSParent , WBS , StartActual) values
(NULL, 225, null)
,(225, 2251, null)
,(2251, 22511, null)
,(22511, 225111, null)
,(22511, 225112, null)
,(22511, 225113, null)
,(22511, 225114, null)
,(22511, 225115, null)
,(22511, 225116, null)
,(22511, 225117, 2022-10-23)
,(22511, 225118, 2022-11-01)
,(225, 2252, null)
,(2252, 22521, null)
,(22521, 225211, null)
,(22521, 225212, null)
,(22521, 225213, null)
,(22521, 225214, 2022-12-23)
,(22521, 225215, null)
,(22521, 225216, 2022-08-01)
,(22521, 225217, null);
,(22521, 225218, null);

finally I get answer according Recursive sum in tree structure
with C as
(
select
T.RowNo,
T.ID,
T.StartActual,
T.ID as RootID
from MSP.MSPMAIN T
union all
select
T.RowNo,
T.ID,
T.StartActual,
C.RootID
from MSP.MSPMAIN T
inner join C
on T.ID_Parent = C.ID
)
select
T.RowNo,
T.ID,
T.ID_Parent,
T.StartActual,
S.MINeveryNode
from MSP.MSPMAIN T
inner join (
select RootID,
MIN(StartActual) as MINeveryNode
from C
group by RootID
) as S
on T.Id = S.RootID
order by T.RowNo
option (maxrecursion 0)

Related

Optional parameters in cursor where clause

I have the following sample query which takes values from procedure parameters. The parameter can be either passed or default to null.
SELECT * FROM table
WHERE( table_term_code = '201931'
OR (table_term_code = '201931' and table_DETL_CODE ='CA02')
OR ( table_term_code = '201931' and table_ACTIVITY_DATE = sysdate)
OR ( table_term_code = '201931' and table_SEQNO = NULL));
i.e the user can input term code and not input any other parameter, or can input term code and table_DETL_CODE and not any other input parameter.
Same goes for the other 2 or conditions.
If a term code is passed and table_DETL_CODE is null, the query should return all the values for that term_code, whereas this query returns null.
Is there a way to achieve this without case or if conditions in PL/SQL?
If I understood you correctly, this might be what you're looking for:
select *
from your_table
where (table_term_code = :par_term_code or :par_term_code is null)
and (table_detl_code = :par_detl_code or :par_detl_code is null)
and (table_activity_date = :par_activity_date or :par_activity_date is null)
and (table_seqno = :par_seqno or :par_seqno is null)
The description seems to that you require user to enter table_term_code and then either none or exactly 1 of the other 3. If so then perhaps:
select *
from your_table
where table_term_code = :par_term_code
and ( (table_detl_code = :par_detl_code and :par_activity_date is null and :par_seqno is null)
or (table_activity_date = :par_activity_date and :par_detl_code is null and :par_seqno is null)
or (table_seqno = :par_seqno and :par_detl_code is null and :par_activity_date is null)
or (table_seqno is null and :par_detl_code is null and :par_activity_date is null)
);

join, group by and count sql to linq conversion

Query:
SELECT COUNT(*) as Avalied
FROM LeaveMaster as lm
JOIN LeaveSubsidary as ls
ON lm.TransMasterId = ls.TransMasterId
WHERE lm.SystemCode = 'abc123' AND lm.EmployeeCode = '0014' AND lm.Status ='Approved'
Group by ls.Leave_Type
How would you convert the above sql query to linq? Thanks :)
Edit :
from p in db.PY_LeaveTransactionMasterTAB.AsEnumerable()
join e in db.PY_LeaveTransactionSubsidaryTAB.AsEnumerable() on p.LV_TransMasterId equals e.LV_TransMasterId into grp
where p.SystemCode == SysCode && p.EmployeeCode == EmpCode && p.Status == "Approved"
group grp by e.Leave_Type // This line is invalid Why?
The above is what I have tried so far, why can't I do e.Leave_Type or what is the right way to do group grp by e.Leave_Type?
You could try this:
(from p in db.PY_LeaveTransactionMasterTAB
join e in db.PY_LeaveTransactionSubsidaryTAB on p.LV_TransMasterId equals e.LV_TransMasterId
where p.SystemCode == SysCode && p.EmployeeCode == EmpCode && p.Status == "Approved"
group new {p,e} by new {e.Leave_Type } into gr
select new
{
Leave_Type = gr.Key.Leave_Type ,
Count = gr.Count()
}).ToList();

Zend select object - building a query

How can I write the query below in Zend Select object notation so using ->join()->where() etc?
SELECT t.id, t.user_id, t.added_date, u.id, u.phone, bk.call_status
FROM `transaction` t
INNER JOIN
(
SELECT id, MAX(added_date) AS addedDate
FROM `transaction`
GROUP BY id
) gt
ON t.id = gt.id AND t.added_date = gt.addedDate
LEFT JOIN `user` u ON t.user_id = u.id
LEFT JOIN `bok_call` bk ON bk.user_id = t.user_id
WHERE NOT t.user_id = 'null'
AND addedDate BETWEEN '2008-05-04 17:51:48' AND '2009-05-04 17:51:48'
AND NOT u.phone = ''
AND bk.call_status IS null
For example this way:
$joinSelect = $model->select()
->from('transaction'), array('id', 'addedDate' => 'MAX(added_date)'))
->group('id');
$select = $model->select()
->setIntegrityCheck(false)
->from(array('t' => 'transaction'), array('id', 'user_id', 'added_date'))
->join(array('gt' => $joinSelect), 't.id = gr.id AND t.added_date = gt.addedDate', array());
->joinLeft(array('u' => 'user'), 't.user_id = u.id', array('id', 'phone'))
->joinLeft(array('bk' => 'bok_call'), 'bk.user_id = t.user_id', array('call_status'))
->where('t.user_id != ?', 'null')
->where("addedDate BETWEEN '2008-05-04 17:51:48' AND '2009-05-04 17:51:48')
->where('u.phone != ?', '')
->where('bk.call_status IS NULL');
Be aware that you won't be able to differentiate 't.id' and 'u.id' in result.

INNER JOIN LEFT JOIN in LINQ to SQL

How to convert INNER JOIN and LEFT JOIN in the following SQL query to LINQ to SQL? Thanks!
SELECT transactions.postdate,
transactions.clientkey AS TransClientKey,
transactions.type AS TransType,
clients.clientno,
Isnull(clients.nostmt, 0) AS CliNoStmt,
Isnull(aging.nostmt, 0) AS AgeNoStmt,
pmtchecks.*
FROM ((pmtchecks
INNER JOIN transactions
ON pmtchecks.transkey = transactions.transkey)
INNER JOIN clients
ON transactions.clientkey = clients.clientkey)
LEFT JOIN aging
ON ( transactions.clientkey = aging.clientkey )
AND ( pmtchecks.debtorkey = aging.debtorkey )
WHERE ( pmtchecks.debtorkey = 36927 )
AND ( transactions.status = 0 )
AND ( transactions.postdate <= '31-May-2012' )
AND ( ( transactions.postdate >= '01-May-2012' )
OR ( clients.clientno = 'UNKNOWN' ) )
ORDER BY pmtchecks.checkdate,
pmtchecks.checkno
Hi this is kind of dummy code i cnt say its exactly right but the idea will be exactly same to get the result
var anonymousType= (from pm in pmtchecks
join tr in transactions
on pm.transkey equals tr.transkey //INNERJOIN
join cl in clients
on tr.clientKey equals cl.clientKey
join ag in aging
on pm.debtorkey equals ag.debtorKey into ljoin //Left Join
from lj in ljoin.DefaultOrEmpty()
where pm.debortkey==36927 && tr.status==0 && tr.postdate<="31-May-2012" && tr.postdate>="01-May-2012" //u will have to change this to date format first
Select new {PostDate=tr.postdate, TransClientKey=tr.clientkey,TransType=tr.type,ClientNo=cl.clientno,CliNoStmt=cl.nomst ?? 0,AgeNoStmt=ag.nomst ??0,Pmtchecks=pm } //Anonymous type from this you can extract the values and fill to your custom type
).OrderBy(o=>o.Pmtchecks.checkdate).OrderBy(o=>o.Pmtchecks.checkno).ToList();
Hope this will help.
LINQ Query Samples
EDITED
var pmtchecks = from p in urcontext.pmtchecks
join t in urcontext.transactions on p.transkey equals t.transkey
join a in urcontext.aging on t.clientkey equals a.clientkey into details
from d in details.Where( a => ( a.debtorkey == p.debtorkey)).DefaultIfEmpty()
where (p.debtorkey == 36927 && t.status == 0 && t.postdate <= '31-May-2012'
&& (t.postdate >= '01-May-2012' || c.clientno == 'UNKNOWN' ))
orderby p.checkdate, p.checkno
select new
{
t.postdate,
t.clientkey,
// TransClientKey = t.clientkey, //only works if TransClientKey is property
t.type ,
//TransTypet = t.type ,//property
c.clientno,
c.nostmt,
//CliNoStmt = c.nostmt ?? 0,//property
a.nostmt//,
//AgeNoStmt = nostmt ?? 0,//property
//p. ... //follow above for p columns
};

Linq to SQL query taking forever

Ok, first I thought I had a problem with how I was querying things. But apparently the problem lies in how linq translates my query to sql.
Here's my linq:
var items = (from p in ctx.bam_Prestatie_AllInstances
join q in ctx.bam_Zending_AllRelationships on p.ActivityID equals q.ReferenceData
join r in ctx.bam_Zending_AllInstances on q.ActivityID equals r.ActivityID
orderby p.LastModified descending
where r.PrestatieOntvangen >= vanaf && r.PrestatieOntvangen <= tm
select new Data.BAMPrestatieInstance
{
Aanvaard = p.PrestatieAanvaard,
Contactnummer = r.ContactNr,
Identificatie = p.Identificatie,
Foutmelding = ((p.Foutmelding == "" || p.Foutmelding == null) && p.PrestatieAanvaard == null) ? "De prestatie is bezig met verwerkt te worden." : p.Foutmelding.Replace("\r\n", " "),
Ontvangen = p.PrestatieZendingOntvangen,
Uitvoerdatum = p.Uitvoerdatum.Replace('-', '/'),
Zender = r.Zender,
PrestatieCode = p.PrestatieCode,
ZendingsNr = r.Zendingnummer.ToString(),
GroepsAanvaarding = r.Identificatie
}).Take(100);
Which gets translated in:
SELECT TOP (100) [t3].[Zender], [t3].[ContactNr] AS [Contactnummer], [t3].[Identificatie], [t3].[value] AS [Uitvoerdatum], [t3].[PrestatieZendingOntvangen] AS [Ontvangen], [t3].[PrestatieAanvaard] AS [Aanvaard], [t3].[value2] AS [Foutmelding], [t3].[PrestatieCode], [t3].[value3] AS [ZendingsNr], [t3].[Identificatie2] AS [GroepsAanvaarding]
FROM (
SELECT [t2].[Zender], [t2].[ContactNr], [t0].[Identificatie], REPLACE([t0].[Uitvoerdatum], #p0, #p1) AS [value], [t0].[PrestatieZendingOntvangen], [t0].[PrestatieAanvaard],
(CASE
WHEN (([t0].[Foutmelding] = #p2) OR ([t0].[Foutmelding] IS NULL)) AND ([t0].[PrestatieAanvaard] IS NULL) THEN CONVERT(NVarChar(3800),#p3)
ELSE REPLACE([t0].[Foutmelding], #p4, #p5)
END) AS [value2], [t0].[PrestatieCode], CONVERT(NVarChar,[t2].[Zendingnummer]) AS [value3], [t2].[Identificatie] AS [Identificatie2], [t2].[PrestatieOntvangen], [t0].[LastModified]
FROM [dbo].[bam_Prestatie_AllInstances] AS [t0]
INNER JOIN [dbo].[bam_Zending_AllRelationships] AS [t1] ON [t0].[ActivityID] = [t1].[ReferenceData]
INNER JOIN [dbo].[bam_Zending_AllInstances] AS [t2] ON [t1].[ActivityID] = [t2].[ActivityID]
) AS [t3]
WHERE ([t3].[PrestatieOntvangen] >= #p6) AND ([t3].[PrestatieOntvangen] <= #p7)
ORDER BY [t3].[LastModified] DESC
As you can see, first it selects EVERYTHING and then it takes the top 100 and does the where. Why is this? Why can't it directly do the top 100, I think the problem why my queries run so long is because of this. Is there a better way to construct my linq query then?
Thanks
Try this:
var items = from p in ctx.bam_Prestatie_AllInstances.OrderByDesc(p => p.LastModified).Take(100)
join q in ctx.bam_Zending_AllRelationships on p.ActivityID equals q.ReferenceData
join r in ctx.bam_Zending_AllInstances on q.ActivityID equals r.ActivityID
where r.PrestatieOntvangen >= vanaf && r.PrestatieOntvangen <= tm
select new Data.BAMPrestatieInstance
{
Aanvaard = p.PrestatieAanvaard,
Contactnummer = r.ContactNr,
Identificatie = p.Identificatie,
Foutmelding = ((p.Foutmelding == "" || p.Foutmelding == null) && p.PrestatieAanvaard == null) ? "De prestatie is bezig met verwerkt te worden." : p.Foutmelding.Replace("\r\n", " "),
Ontvangen = p.PrestatieZendingOntvangen,
Uitvoerdatum = p.Uitvoerdatum.Replace('-', '/'),
Zender = r.Zender,
PrestatieCode = p.PrestatieCode,
ZendingsNr = r.Zendingnummer.ToString(),
GroepsAanvaarding = r.Identificatie
};
Since the sort applies only to your first table, I'd try to force the order by and take 100 to be applied before the join.