Can you help me to write recursive query for two tables? - sql

I need to write recursive query for finding all child nodes in this tables.
For example i need find all child ExecutorTasks for ParentManagerTaskId = 6
ManagerTasks
{
Id,
ParentExecutorTaskId
}
ExecutorTasks
{
Id,
ParentManagerTaskId
}
;WITH query AS
(
SELECT et.Id,et.ParentManagerTaskId,mt.ParentExecutorTaskId
FROM [Planning.ExecutorTasks] et
left outer join [Planning.ManagerTasks] mt on et.ParentManagerTaskId=mt.Id
WHERE mt.Id = 6
UNION ALL
SELECT q.Id, q.ParentManagerTaskId,et.Id
FROM [Planning.ExecutorTasks] et
JOIN query q ON et.Id = q.Id
)
SELECT *
FROM query

Your model is a little misleading since you have 2 tables that are related against each other and you only want to display records from one. This means you have to do 2 joins on the recursive part to get the children of the related entity.
Try with the following:
;WITH Recursion AS
(
-- Anchor
SELECT
ExecutorTaskId = E.Id,
RecursionLevel = 0
FROM
[Planning.ExecutorTasks] AS E
WHERE
E.ParentManagerTaskId = 6
UNION ALL
-- Further childs
SELECT
ExecutorTaskId = E.Id,
RecursionLevel = R.RecursionLevel + 1
FROM
Recursion AS R
INNER JOIN [Planning.ManagerTasks] AS M ON R.ExecutorTaskId = M.ParentExecutorTaskId
INNER JOIN [Planning.ExecutorTasks] AS E ON M.Id = E.ParentManagerTaskId
)
SELECT
R.RecursionLevel,
R.ExecutorTaskId
FROM
Recursion AS R
ORDER BY
R.RecursionLevel,
R.ExecutorTaskId
I can't test if you don't supply example values, expected outcome and table's DDL.

Related

SQL split repeating rows caused by UNION

I am writing a query to look through and get two seperate averages based on where conditions.
I tried two select statetments but ended up with lots of duplicates.
Now I have a union which works pretty well, although I have my two fields in alternating rows instead of seperate columns.
Can anyone suggest a fix, sorry for the dodgy code!
SELECT
tblSkillName.skillName,
tblTestScores.skillUID,
AVG(tblTestScores.percentage) AS `cohortPercentage`
FROM
(
(
(
tblTestScores
INNER JOIN tblUsers ON tblUsers.email = tblTestScores.email
)
INNER JOIN tblTestDetails ON tblTestScores.testDetailsID = tblTestDetails.testDetailsID
)
INNER JOIN tblSkillName ON tblSkillName.skillUID = tblTestScores.skillUID
)
WHERE
teacherGroup = '9JS2/Cp'
AND tblTestScores.testDetailsID = 1
GROUP BY
skillName
UNION ALL
SELECT
tblSkillName.skillName,
tblTestScores.skillUID,
AVG(tblTestScores.percentage) AS `groupPercentage`
FROM
(
(
(
tblTestScores
INNER JOIN tblUsers ON tblUsers.email = tblTestScores.email
)
INNER JOIN tblTestDetails ON tblTestScores.testDetailsID = tblTestDetails.testDetailsID
)
INNER JOIN tblSkillName ON tblSkillName.skillUID = tblTestScores.skillUID
)
WHERE
tblTestScores.testDetailsID = 1
GROUP BY
skillName
ORDER BY
skillUID ASC

Re-writting the query without "Connect By "

I am rewriting the query to replace to remove CONNECT BY:
SELECT *
FROM ADM_TRT AT
INNER JOIN UTILISATEUR U
ON U.UTI_ID = AT.UTI_ID
INNER JOIN
(
SELECT CM.MAI_ID
FROM CON_MAI CM
CONNECT BY CM.MAI_PER_RES = PRIOR CM.MAI_ID
START WITH CM.MAI_ID IN (
SELECT MAJ_ID
FROM DROIT_LOGIN
WHERE LOG_ID = 21543
)
) CON_MAI_FILTERED_ON_LOGIN
ON AT.TRT_MAI_ID = CON_MAI_FILTERED_ON_LOGIN.MAI_ID;
For CONNECT BY Part , I wrote this
WITH tree (MAI_ID,MAI_PER_RES, level1) AS (
SELECT MAI_PER_RES, MAI_ID, 1 as level1 FROM CON_MAI
UNION ALL
SELECT child.MAI_ID, child.MAI_PER_RES, parent.level1 + 1
FROM CON_MAI child --Line 20
JOIN tree parent
on parent.MAI_PER_RES = child.MAI_ID
)
SELECT MAI_ID FROM tree
But I am stuck to integrate this in subquery in the CONNECT BY sub-query. Can someone please help to integrate this?
It looks like you have the recursion reversed in the recursive sub-query and can use:
WITH tree (MAI_ID) AS (
SELECT MAI_ID
FROM CON_MAI
WHERE MAI_ID IN ( SELECT MAJ_ID
FROM DROIT_LOGIN
WHERE LOG_ID = 21543 )
UNION ALL
SELECT c.MAI_ID
FROM CON_MAI c
JOIN tree p
on c.MAI_PER_RES = p.MAI_ID
)
SELECT *
FROM ADM_TRT AT
INNER JOIN UTILISATEUR U
ON U.UTI_ID = AT.UTI_ID
INNER JOIN tree CON_MAI_FILTERED_ON_LOGIN
ON AT.TRT_MAI_ID = CON_MAI_FILTERED_ON_LOGIN.MAI_ID;
(untested as I do not have your tables or data)

Foreach loop on two SQL tables

I have two tables which are totally independent from each other, and I need to extract information from both of them and generate a CSV.
I'm doing this query:
SELECT NOM_FLUX, TYPE_CONTENU, DATE_DEPOT_GED
FROM FLUX_GED
WHERE TYPE_CONTENU = 'TEMPO_COURRIER_FSS'
AND NOM_FLUX NOT LIKE 'PCC%'
With this result:
Then I'm doing a query from this result with the ID
Like This (on the first result)
SELECT ID, URL_RELATIVE, TYPE_CONTENU, NOM_ELEMENT
FROM ELEMENT_GED
WHERE ID IN (
SELECT ID_ELEMENT
FROM SUIVI_GED
WHERE ID_FLUX IN (18682403)
)
With this result:
And here is the information from the SUIVI_GED table:
First I would like to do like a PowerShell foreach loop on every ID of my first query and then export the result of both query in a common csv.
I would like a result like that for my csv:
NOM_FLUX;URL_RELATIVE;TYPE_CONTENU;NOM_ELEMENT
infoNomFlux;infoURL;infoType;infoNOM
You seem to want join. A rather literal translation of your queries would be:
select
f.nom_flux,
f.type_contenu as type_contenu_flux,
f.date_depot_ged ,
e.id,
e.url_relative,
e.type_contenu as type_contenu_element,
e.nom_element
from flux_ged f
inner join element_ged e
on exists (select 1 from suivi_ged s where s.id_flux = f.id and e.id = s.id)
where
f.type_contenu = 'TEMPO_COURRIER_FSS'
and f.nom_flux not like 'PCC%'
Depending on your actual design, you might be able to flatten the exists condition as another join:
select
f.nom_flux,
f.type_contenu as type_contenu_flux,
f.date_depot_ged ,
e.id,
e.url_relative,
e.type_contenu as type_contenu_element,
e.nom_element
from flux_ged f
inner join suivi_ged s on s.id_flux = f.id
inner join element_ged e on e.id = s.id
where
f.type_contenu = 'TEMPO_COURRIER_FSS'
and f.nom_flux not like 'PCC%'

PostgreSQL - how to query "result IN ALL OF"?

I am new to PostgreSQL and I have a problem with the following query:
WITH relevant_einsatz AS (
SELECT einsatz.fahrzeug,einsatz.mannschaft
FROM einsatz
INNER JOIN bergefahrzeug ON einsatz.fahrzeug = bergefahrzeug.id
),
relevant_mannschaften AS (
SELECT DISTINCT relevant_einsatz.mannschaft
FROM relevant_einsatz
WHERE relevant_einsatz.fahrzeug IN (SELECT id FROM bergefahrzeug)
)
SELECT mannschaft.id,mannschaft.rufname,person.id,person.nachname
FROM mannschaft,person,relevant_mannschaften WHERE mannschaft.leiter = person.id AND relevant_mannschaften.mannschaft=mannschaft.id;
This query is working basically - but in "relevant_mannschaften" I am currently selecting each mannschaft, which has been to an relevant_einsatz with at least 1 bergefahrzeug.
Instead of this, I want to select into "relevant_mannschaften" each mannschaft, which has been to an relevant_einsatz WITH EACH from bergefahrzeug.
Does anybody know how to formulate this change?
The information you provide is rather rudimentary. But tuning into my mentalist skills, going out on a limb, I would guess this untangled version of the query does the job much faster:
SELECT m.id, m.rufname, p.id, p.nachname
FROM person p
JOIN mannschaft m ON m.leiter = p.id
JOIN (
SELECT e.mannschaft
FROM einsatz e
JOIN bergefahrzeug b ON b.id = e.fahrzeug -- may be redundant
GROUP BY e.mannschaft
HAVING count(DISTINCT e.fahrzeug)
= (SELECT count(*) FROM bergefahrzeug)
) e ON e.mannschaft = m.id
Explain:
In the subquery e I count how many DISTINCT mountain-vehicles (bergfahrzeug) have been used by a team (mannschaft) in all their deployments (einsatz): count(DISTINCT e.fahrzeug)
If that number matches the count in table bergfahrzeug: (SELECT count(*) FROM bergefahrzeug) - the team qualifies according to your description.
The rest of the query just fetches details from matching rows in mannschaft and person.
You don't need this line at all, if there are no other vehicles in play than bergfahrzeuge:
JOIN bergefahrzeug b ON b.id = e.fahrzeug
Basically, this is a special application of relational division. A lot more on the topic under this related question:
How to filter SQL results in a has-many-through relation
Do not know how to explain it, but here is an example how I solved this problem, just in case somebody has the some question one day.
WITH dfz AS (
SELECT DISTINCT fahrzeug,mannschaft FROM einsatz WHERE einsatz.fahrzeug IN (SELECT id FROM bergefahrzeug)
), abc AS (
SELECT DISTINCT mannschaft FROM dfz
), einsatzmannschaften AS (
SELECT abc.mannschaft FROM abc WHERE (SELECT sum(dfz.fahrzeug) FROM dfz WHERE dfz.mannschaft = abc.mannschaft) = (SELECT sum(bergefahrzeug.id) FROM bergefahrzeug)
)
SELECT mannschaft.id,mannschaft.rufname,person.id,person.nachname
FROM mannschaft,person,einsatzmannschaften WHERE mannschaft.leiter = person.id AND einsatzmannschaften.mannschaft=mannschaft.id;

Multiple MAX values select using inner join

I have query that work for me only when values in the StakeValue don't repeat.
Basically, I need to select maximum values from SI_STAKES table with their relations from two other tables grouped by internal type.
SELECT a.StakeValue, b.[StakeName], c.[ProviderName]
FROM SI_STAKES AS a
INNER JOIN SI_STAKESTYPES AS b ON a.[StakeTypeID] = b.[ID]
INNER JOIN SI_PROVIDERS AS c ON a.[ProviderID] = c.[ID] WHERE a.[EventID]=6
AND a.[StakeGroupTypeID]=1
AND a.StakeValue IN
(SELECT MAX(d.StakeValue) FROM SI_STAKES AS d
WHERE d.[EventID]=a.[EventID] AND d.[StakeGroupTypeID]=a.[StakeGroupTypeID]
GROUP BY d.[StakeTypeID])
ORDER BY b.[StakeName], a.[StakeValue] DESC
Results for example must be:
[ID] [MaxValue] [StakeTypeID] [ProviderName]
1 1,5 6 provider1
2 3,75 7 provider2
3 7,6 8 provider3
Thank you for your help
There are two problems to solve here.
1) Finding the max values per type. This will get the Max value per StakeType and make sure that we do the exercise only for the wanted events and group type.
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
2) Then we need to get only one return back for that value since it may be present more then once.
Using the Max Value, we must find a unique row for each I usually do this by getting the Max ID is has the added advantage of getting me the most recent entry.
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
3) Now that we have the ID's of the rows that we want, we can just get that information.
SELECT Stakes.ID, Stakes.StakeValue, SType.StakeName, SProv.ProviderName
FROM SI_STAKES AS Stakes
INNER JOIN SI_STAKESTYPES AS SType ON Stake.[StakeTypeID] = SType.[ID]
INNER JOIN SI_PROVIDERS AS SProv ON Stake.[ProviderID] = SProv.[ID]
WHERE Stake.ID IN (
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
)
You can use the over clause since you're using T-SQL (hopefully 2005+):
select distinct
a.stakevalue,
max(a.stakevalue) over (partition by a.staketypeid) as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
Essentially, this will find the max a.stakevalue for each a.staketypeid. Using a distinct will return one and only one row. Now, if you wanted to include the min a.id along with it, you could use row_number to accomplish this:
select
s.id,
s.maxvalue,
s.staketypeid,
s.providername
from (
select
row_number() over (order by a.stakevalue desc
partition by a.staketypeid) as rownum,
a.id,
a.stakevalue as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
) s
where
s.rownum = 1