Query to serialize data - sql

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.

Related

T-SQL How to configure Group by so that specific values would be correctly shown

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

SELECT COUNT of child records as subquery within UNION

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.

Make a query to display unmatched data

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);

T-SQL get all nodes and their last level children using common table expression

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.

SQL Inner Join and Partitioning To obtain RowNumbers when matching

I have 2 tables. The first table 'a' the second 'b'.
I am writing a query that grabs every row in table a (there is 33 rows defined) and inner joins table b where the EnclLocation or the BackPanLoc match the Workcell in table A.
I only want a row from table B where they match based off BackPan and EnclLocation but they are not the same records. table b has a few rows of data that is assigned to the same workcell as table a. I am just trying to retrieve those additional rows and partition it.
I attached table a and table b. I also attached the desired results for this query with respect to Workcell 10 only as an example... As you can see, table B has 4 records that has either the EnclLocation or the BackPanLoc = 10. But my results only show the same DelvNumber 4 times. any help is most appreicated.
Table a
Table b
Incorrect Results
Desired Results (showing only Workcell 10 as an example)
workcell DelvNumber RowNum
1 447910-02 1
2 445710-01 1
2 445710-01 2
3 444291-01 1
3 444291-01 2
4 447910-03 1
4 447910-03 2
5 648020-01 1
6 647800-02 1
7 646920-01 1
7 646920-01 2
8 644830-4-8 1
8 644830-4-8 2
9 443990-01 1
10 645960-01-03 1
10 445710-11 2
10 445710-02 3
10 445710-09 4
Code Used
WITH ss
AS (SELECT a.*,
Row_number()
OVER(
partition BY a.workcell
ORDER BY a.workcell) AS rownum
FROM nwcurrent a
INNER JOIN nwdeliverables b
ON b.encllocation = a.workcell
OR b.backpanloc = a.workcell
WHERE ( b.status < 9
AND ( b.encllocation <> 0
OR b.backpanloc <> 0 )
OR a.delvnumber = '123' ))
SELECT *
FROM ss
copy and paste format
1 447910-02 1
2 445710-01 1
2 445710-01 2
3 444291-01 1
3 444291-01 2
4 447910-03 1
4 447910-03 2
5 648020-01 1
6 647800-02 1
7 646920-01 1
7 646920-01 2
8 644830-4-8 1
8 644830-4-8 2
9 443990-01 1
10 645960-01-03 1
10 445710-11 2
10 445710-02 3
10 445710-09 4
SQLFiddle
http://sqlfiddle.com/#!3/a8682/4
A new try...
SELECT a.workcell
,a.DelvNumber AS A_DelvNumber
,b.DelvNumber AS B_DelvNumber
,CASE WHEN a.DelvNumber<>b.DelvNumber THEN b.DelvNumber ELSE a.DelvNumber END AS DelvNumber_Resolved
,Row_number() OVER(partition BY a.workcell ORDER BY a.workcell) AS rownum
FROM NWCurrent a
INNER JOIN NWDeliverables AS b ON b.EnclLocation=a.WorkCell OR b.BackPanLoc=a.WorkCell
WHERE (b.status <9 AND (b.EnclLocation<>0 OR b.BackPanLoc<>0)OR a.DelvNumber='123')