I'm trying to get a count of the number of children associated with a user. The portion of this query that selects the number of children records is: (select count(*) from blitz_user as ua where ua.manager_id= u.id ) as "directsCount".
The query selects the correct number of children for all records except those with zero (0) children. For records with zero children the value of directsCount is still one (1).
The database in use is PostgreSQL. Please let me know if this is easier to understand with sample data. I tried to limit the length of the post in case that is not helpful.
WITH RECURSIVE subordinates AS (
SELECT u.id,
u.company_id as "companyId",
u.manager_id as "managerId",
1 as levels_down,
(select count(*) from blitz_user as ua where ua.manager_id= u.id ) as "directsCount"
FROM blitz_user AS u
WHERE u.manager_id = 9
UNION
SELECT u.id,
u.company_id as "companyId",
u.manager_id as "managerId",
levels_down + 1, 1 as levels_down
FROM blitz_user AS u
INNER JOIN subordinates AS s ON u.manager_id = s.id
WHERE levels_down <= 5
)
SELECT id, "companyId", "managerId", levels_down, "directsCount"
FROM subordinates;
Please see the following dbfiddle for example code along with the current output.
https://dbfiddle.uk/?rdbms=postgres_12&fiddle=509411d5971efc4eddfccabf3c4d22a4
The current output is:
id companyId managerId levels_down directsCount
10 6 9 1 2 (correct)
11 6 9 1 1 (correct)
12 6 9 1 2 (correct)
13 6 9 1 3 (correct)
14 6 13 2 1 (should be 2)
15 6 13 2 1 (should be 2)
16 6 13 2 1 (correct)
41 6 10 2 1 (should be 3)
45 6 10 2 1 (should be 3)
49 6 11 2 1 (should be 4)
54 6 12 2 1 (should be 0)
58 6 12 2 1 (should be 3)
17 6 14 3 1 (should be 4)
<snip>
The problem just repeats at this point for all remaining rows.
The "levels_down" tracks how far down the hierarchy we are. The values for "directsCount" are correct when we are only 1 levels_down, but then default to "1" for all levels_down from 2, 3, etc.
Related
My current T-SQL query provides the following results:
Query:
WITH CTE AS
(
SELECT SubscriberID, sum(valueMB) as ValuesMB
FROM dbo.InternetNetwork
GROUP BY SubscriberID
),
CTE2 AS (
SELECT ab.planID, a.SubscriberID, MAX(ValuesMB) as MaximumValue
FROM CTE AS a
left join
Subscriber as ab on a.SubscriberID= ab.SubscriberID
GROUP BY ab.planID, a.SubscriberID
)
select *
FROM CTE2 as b
ORDER BY b.MaximumValue desc
Output:
planID | SubscriberID | MaxValue
19 1555 97536.00
18 3528 97478.00
2 4029 93413.00
Query #2:
WITH CTE AS
(
SELECT SubscriberID, sum(valueMB) as ValuesMB
FROM dbo.InternetNetwork
GROUP BY SubscriberID
),
CTE2 AS(
SELECT ab.planID, MAX(ValuesMB) as MaximumValue
FROM CTE AS a
left join
Subscriber as ab on a.SubscriberID= ab.SubscriberID
GROUP BY ab.planID
)
SELECT pl.OperatorID, MAX(b.MaximumValue) as Super
FROM CTE2 as b
left join
Plan as pl on b.planID= pl.planID
GROUP BY pl.operatorID
ORDER BY pl.operatorID
Output #2:
OperatorID | Value
1 93413.00
2 86017.00
3 97536.00
I would like to also include a subscriberID, but I'm unable to figure out a way to do so, as the only way to do it, is including in the last SELECT and adding to GROUP BY, which when done, makes a mess of a result which is not accurate.
My desired output:
OperatorID | Value | SubscriberID
1 93413.00 4029
2 86017.00 164
3 97536.00 1544
internet network data:
SubscriberID ValuesMB
1 28
1 27
2 27
2 27
2 27
3 29
3 28
3 27
3 27
4 27
4 27
4 29
Subscriber Data:
SubscriberID PersonID PlanID
1 1 3
2 2 10
3 2 6
4 3 14
5 3 1
6 4 18
7 5 5
8 5 1
9 5 9
10 5 16
11 6 13
12 6 13
13 6 20
14 6 16
15 7 4
Plan data
PlanID OperatorID
1 1
2 1
3 2
4 2
5 2
6 2
7 2
8 2
9 2
10 2
11 2
12 3
13 3
14 3
15 3
16 3
17 3
18 3
19 3
20 3
The tables are somewhat like this related InternetNetwork-> Subscriber -> Plan. InternetNetwork contains how much each Subscribed has used. Each Subscriber has Plan associated with him. Each Plan contains a different Operator, there are only three. I wish to list all three operators, the data transferred by the subscriber of the plan that has the operator and Subscriber ID.
Window functions allow you to have fields in your select along with aggregate functions. You can do something like this
;WITH CTE AS
(
SELECT I.SubscriberID,
S.PlanID,
SUM(ValuesMB) OVER(PARTITION BY i.SubscriberID)as ValuesMB
FROM dbo.InternetNetwork I
JOIN Subscriber S
ON I.SubscriberID = S.SubscriberID
),
CTE2 AS
(
SELECT p.operatorID,
a.SubscriberID,
a.ValuesMB,
ROW_NUMBER() OVER(PARTITION BY p.operatorID ORDER BY a.ValuesMB DESC) as rn
FROM CTE a
join [Plan] P
on a.planID = P.planID
)
SELECT operatorID,
ValuesMB,
SubscriberID
FROM CTE2
where rn = 1
I m having difficulty making a query that displays unmatched data in between 2 tables.
The tables are:
Employee data Salary data
ID Holidays ID Holiday
1 10 0 10
2 8 1 5
3 5 2 8
4 7 3 5
5 8 7 6
6 5 8 9
7 6 9 2
8 9 10 3
the primary key is ID for both tables.
I want my query result to contain all the values that does not match in both tables.
The type of output i want is something like this:
ID Holiday
0 10
1 10
1 5
4 7
5 8
6 5
9 2
10 3
I tried using unmatched query wizard but that only compares ID, not the Holiday column.
Please help me!
You could use a union of two exists queries:
SELECT ID, Holiday FROM Employee as e
WHERE NOT EXISTS (SELECT 1 FROM Salary as s WHERE s.ID = e.ID AND s.Holiday = e.Holiday)
UNION ALL
SELECT ID, Holiday FROM Salary as s
WHERE NOT EXISTS (SELECT 1 FROM Employee as e WHERE e.ID = s.ID AND e.Holiday = s.Holiday);
I need the last level children of all nodes between the last level and the parent. I am new to recursive ctes and trying to get this result.
Consider the following table:
emp id | mgr id
1 null
2 1
3 1
4 1
5 2
6 2
7 3
8 3
9 4
10 4
11 5
12 6
13 6
14 6
15 11
if the input is (15) then the output should be
mgr id emp id
2 12
2 13
2 14
2 15
5 15
6 12
6 13
6 14
11 15
Searching around the web I figured this can be done using recursive queries but I am unable to.
with cte as
(
select
emp_id, mgr_id
from
emp_heirarchy
where
emp_id in (select MIN(lt.emp_id)
from landing_table lt
inner join emp_heirarchy eh on lt.emp_id = eh.emp_id
group by mgr_id)
union all
select
eh.emp_id, eh.mgr_id
from
emp_heirarchy eh
inner join
cte c on c.mgr_id = eh.emp_id
)
select distinct *
from cte
order by mgr_id
I have tried a few other versions of the above query with no luck.
Looking at the below data is there an easy way to find IDs that exist at a higher level under the same leaf and remove them.
E.g. ID 4,5 exists in rows 4,5 , 8,9 and 12,13.
i want to remove rows 4,5 as the same IDs exist further down the hierarchy (rows 8,9), but rows 12,13 stay as they are on a separate leaf.
Rows to be Removed
row ID Path
1 1 /1/
2 2 /1/2/
3 3 /1/2/3/
4 4 /1/2/3/4/
5 5 /1/2/3/5/
6 6 /1/2/3/6/
7 7 /1/2/3/6/7/
8 4 /1/2/3/6/4/
9 5 /1/2/3/6/5/
10 8 /1/2/8/
11 7 /1/2/8/7/
12 4 /1/2/8/4/
13 5 /1/2/8/5/
example for max ID len = 1
select *
--delete t1
from table as t1
where exists(
select *
from table as t2
where left(t2.path, len(t1.path - 2)) = left(t1.path, len(t1.path - 2))
and charindex(right(t1.path, 2), t2.path, len(t1.path)) > 0
)
This is my approach it should work for any length of ID:
with
conversed as (
select substring(reverse(path),CHARINDEX('/',reverse(path),2), len(path)-CHARINDEX('/',reverse(path),2)) inverse_path, id, t.row
from t)
select c.id, c.row keeper, c1.row deletethis
from conversed c join conversed c1
on c.id = c1.id
and c.row <> c1.row
and c.inverse_path like '%' +c1.inverse_path;
OUTPUT
id keeper deletethis
4 8 4
5 9 5
I have two tables:
Routes
ID Description
1 street1
2 street2
3 street3
4 street4
5 street5
Segments
ID RouteID, Progres, LabelStart, LabelEnd
1 1 5 1 A 21 B
2 1 10 2 A 10
3 2 15 3 25
4 2 15 2 20
5 3 20 1 11
6 3 22 4 10
7 4 30 5 11
8 4 31 2 12
I need a sequence with these rules:
table must be ordered by Progress ASC
A column Type is defined and take O if LabelStart and LabelEnd are Odd, E if Even
if two routes have the same progress then the rows are merged in one where
LabelStart is the minimum (among LabelStart Odd and LabelStart Even)
and LabelEnd is the Max, in this case Type takes the value of A (All)
as per example data above the result should be
Sequence
ID RouteID, Progres, LabelStart, LabelEnd Type
1 1 5 1 A 21 B O
2 1 10 2 A 10 E
4 2 15 2 25 A
5 3 20 1 11 O
6 3 22 4 10 E
7 4 30 5 11 O
8 4 31 2 12 E
It is for Postgres 9.2
This was an interesting query to write because you had letters in your LabelStart and LabelEnd fields. I used REGEX_REPLACE to remove those. Then I used a CTE to get the records that had more than one routeid and progress rows.
I think this should do it:
WITH CTE AS (
SELECT
RouteId, Progress
FROM Sequence
GROUP BY RouteId, Progress
HAVING COUNT(DISTINCT Id) > 1
)
SELECT MAX(S.ID) Id,
T.RouteId,
T.Progress,
MIN(regexp_replace(LabelStart, '[^0-9]', '', 'g')) LabelStart,
MAX(regexp_replace(LabelStart, '[^0-9]', '', 'g')) LabelEnd,
'A' as Type
FROM Sequence S
INNER JOIN CTE T ON S.RouteId = T.RouteId AND S.Progress = T.Progress
GROUP BY T.RouteId, T.Progress
UNION
SELECT S.Id,
S.RouteId,
S.Progress,
S.LabelStart,
S.LabelEnd,
CASE
WHEN CAST(regexp_replace(LabelStart, '[^0-9]', '', 'g') as int) % 2 = 0
THEN 'E'
ELSE 'O'
END
FROM Sequence S
LEFT JOIN CTE T ON S.RouteId = T.RouteId AND S.Progress = T.Progress
WHERE T.RouteId IS NULL
ORDER BY Progress ASC
And some sample Fiddle.