I have got data that contains
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
24
32
BB
EE
32
45
EE
DD
45
57
DD
FF
57
62
FF
GG
62
7
GG
FA
81
9
ZZ
GA
What I want to achieve is to have a BOM explosion of it.
What I have come up is the below code:
create table test
( SurrogateKey bigint, ForeignKey bigint,mat_desc varchar,comp_desc varchar );
insert into test
values
( 123, 24,'AA','BB'),
(123,81,'AA','ZZ'),
( 24, 32,'BB','EE'),
( 32, 45,'EE','DD'),
( 45, 57,'DD', 'FF'),
( 57, 62,'FF','GG'),
( 62, 7,'GG','FA'),
(81,9,'ZZ','GA');
With traversal as
( SELECT test.SurrogateKey OriginKey,
ForeignKey,mat_desc,comp_desc
FROM test
WHERE SurrogateKey = 123 -- this first portion of the query generates the beginning set of records.
UNION ALL
SELECT traversal.OriginKey,
test.ForeignKey,traversal.mat_desc,test.comp_desc
FROM test
INNER JOIN traversal
ON test.SurrogateKey = traversal.ForeignKey -- we join back to the result set generated in the previous iteration of the recursion until no more nodes to travel to
)
select * from traversal
That is giving me a result:
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
123
32
AA
EE
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
But what I would like to achieve is to add column to see on which level the child is so thirst three rows would look like this, and so on
parent_id
child_id
parent_desc
child_desc
level
123
24
AA
BB
1
123
81
AA
ZZ
1
123
32
AA
EE
2
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
Maybe someone has got idea, how to solve this. Maybe some window function, or how to come up with some counter to have it using recursive cte
Thank you all in advance
If I understand correctly, you want to enumerate the rows based on the tree-depth. You correctly recognize that you can do this with a recursive CTE.
The syntax for recursive CTEs varies depending on the databases, but the idea is:
with recursive cte as (
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, t.mat_desc as orig_mat_desc, 1 as lev
from test t
where not exists (select 1 from test t2 where t2.comp_desc = t.mat_desc)
union all
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, cte.orig_mat_desc, 1 + lev
from cte join
test t
on cte.comp_desc = t.mat_desc
)
select *
from cte;
Here is a db<>fiddle.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 12 months ago.
Improve this question
table1:
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
ac
65
ac_d
876
table 2:
col1
col2
col3
col4
ab
ab_d
aa
bb
ac
ac_d
ss
pp
this table2 also contains multiple rows
case 1: If I use table1.name = ab as a where condition,
the output should be,
ab, ab_d, aa, bb records
select * from table1 t1
where t1.name = 'ab';
NAME
SAL
ab
34
ab
322
ab_d
34
ab_d
322
aa
34
aa
322
bb
34
bb
322
(or)
case 2: If I use table2.col2 = ac_d as a where condition,
the output should be,
ac, ac_d, ss, pp records
select * from table1 t1
where t1.name = 'ac_d';
NAME
SAL
ac
34
ac
322
ac_d
34
ac_d
322
ss
34
ss
322
pp
34
pp
322
I am unable to write query....
You can do:
select y.*
from table2 x
join table1 y on y.name in (x.col1, x.col2, x.col3, x.col4)
where 'ab' in (x.col1, x.col2, x.col3, x.col4);
Result:
NAME SAL
----- ---
ab 34
ab 322
ab_d 34
ab_d 322
aa 34
aa 322
bb 34
bb 322
See running example at db<>fiddle.
The 3rd table is identical to the first table. Please provide CREATE TABLE scripts with data types, Primary keys and Foreign key constraints.
Looking at the structure of the 2nd table and the values in col2 in the first table I think you are going to need an UNPIVOT command
This will take the 2nd table and use the first column as an entity reference, take the column names from the other columns as use them as attributes and take the column value and use it as the value.
E.g. If you had a table:
Colour Jan Feb Mar
RED 20 15 12
BLUE 8 7 15
The UNPIVOT command would produce
Colour Month Amt
RED Jan 20
RED Feb 15
RED Mar 12
BLUE Jan 8
BLUE Feb 7
BLUE Mar 15
Consider the following table
Dept product name parts WO
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 aa adf 19 1255
32 cc asa 10 7567
32 aa agd 11 1233
31 ss fsf 23 3434
I have around 100 dept. in my table. What I want is that when the dept. is 32 and the product is "aa", I only want to display 30 parts or less. So in this case the total number of parts for aa is 59. So the first aa product has 11 parts and the next aa product has 18 parts so that's 29. It should now ignore all the other aa products.
Expected Output
Dept product name parts WO
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 cc asa 10 7567
31 ss fsf 23 3434
Appreciate any help provided.
Assuming WO is a primary key then use SUM window function to solve it.
SELECT yt.Dept, yt.product, yt.name, yt.parts, yt.WO
FROM yourtable yt
LEFT JOIN (
SELECT *, sum(y.parts) over (partition by y.dept order by y.parts) tsum
FROM yourtable y
WHERE y.product = 'aa'
) t ON yt.WO= t.WO
WHERE yt.dept != 32 or (yt.dept = 32 and t.tsum < 59) or (yt.dept = 32 and yt.product != 'aa')
you can use SUM() window function where you have to partition by dept and product
SELECT dept,
product,
name,
parts,
wo
FROM (SELECT *,
SUM(parts) OVER (PARTITION BY dept, product ORDER BY name) rt
FROM t
) t_rt
WHERE rt <= 30
ORDER BY dept DESC,
product,
wo
Result
dept product name parts wo
32 aa abc 11 1234
32 aa aas 18 2213
32 bb asd 16 3424
32 cc asa 10 7567
31 ss fsf 23 3434
id varname 1area 2area 3area 4area
------------------------------------
1 abc 345 3.7 34 87
1 pqr 46 67 78 55
1 lmn 67 99 33 44
2 xyz 78 78 33 32
I need to calculate SUM of column query.
Is it possible to get column count using while loop?
You probably want to do a SUM() of the Narea column group by your id column like
select id, sum(1area),
sum(2area), sum(3area), sum(4area)
from tbl1
group by id;
I have the following two postgresql tables:
table: daily
id date close symbol_id
1 2016-05-01 80 65
2 2016-05-01 75 67
3 2016-05-01 95 45
4 2016-05-02 11 65
5 2016-05-02 48 67
6 2016-05-02 135 45
7 2016-05-03 18 65
8 2016-05-03 82 67
9 2016-05-03 107 45
10 2016-05-04 29 65
table: symbol
id symbol
65 abc
67 xyz
45 jkl
I need to select all symbols where the close value is less than 100 for the latest date for each symbol. As per the example, not all symbols will have the same latest date.
The following query gives me correct data when I do not use the WHERE clause:
SELECT DISTINCT ON (daily.symbol_id) symbol.symbol, daily.close, daily.date
FROM daily JOIN symbol ON daily.symbol_id = symbol.id
--WHERE daily.close < 100
ORDER BY daily.symbol_id, daily.date DESC
Result:
symbol close date
abc 29 2016-05-04
xyz 82 2016-05-03
jkl 107 2016-05-03
The problem comes when I uncomment the WHERE clause. The desired result is for the symbol jkl to be removed from the list because the value for close for that symbol on its latest date is not < 100. However this is what happens:
symbol close date
abc 29 2016-05-04
xyz 82 2016-05-03
jkl 95 2016-05-01
You can move your existing query to a subquery and then filter with where criteria.
select *
from (
select distinct on (d.symbol_id) s.symbol, d.close, d.date
from daily d
join symbol s on d.symbol_id = s.id
order by daily.symbol_id, daily.date desc
) t
where close < 100
Here's another similar option using a windows function such as row_number:
select *
from (
select d.symbol_id, s.symbol, d.close, d.date,
row_number() over (partition by d.symbol_id order by d.date desc) rn
from daily d
join symbol s on d.symbol_id = s.id
) t
where rn = 1 and close < 100
Code not tested, just to demonstrate idea
First you make a query to get the latest date of every symbol. Then make a join to filter out rows that are not latest which you can safely apply the close < 100 where clause.
SELECT DISTINCT ON(symbol) * FROM (
SELECT MAX(d1.date) latest FROM daily d1 GROUP BY d1.symbol_id
INNER JOIN daily d2 ON latest = d2.date AND d1.symbol_id = d2.symbol_id) t
WHERE close <100
I've been trying to find a way to use the row_number over partition by, but couldn't find how to do so in SQLite.
I'm trying to convert the following the working query from MSSQL syntax to SQLite:
select TKG, hour, CAP, switch, Calls
from
(
select *,
row_number() over(partition by TKG order by cap desc) rn
from yourtable
) t1
where rn = 1
Here's an example with SQLFiddle: http://sqlfiddle.com/#!3/7bf9a/3
Basically, I have the following table:
TKG hour CAP SWITCH CALLS
AAA 7 45 HH 56
AAA 8 35 HH 76
AAA 9 25 HH 43
BBB 7 32 LL 5
BBB 8 43 LL 65
BBB 9 434 LL 65
CCC 7 54 JJ 43
CCC 8 564 JJ 43
CCC 9 54 JJ 65
ddd 7 10 MM 4
ddd 8 10 MM 3
ddd 9 10 MM 5
I need to order by the TKG with the max CAP so the output will look like this:
TKG hour CAP SWITCH CALLS
AAA 7 45 HH 56
BBB 9 434 LL 65
CCC 8 564 JJ 43
ddd 7 10 MM 4
Without knowing unique key it's really hard to do in readable way (no cross apply, no windowed functions). If you can afford to add id into your table, you can do:
select *
from yourtable
where
id in (
select min(y.id)
from yourtable as y
inner join (
select [TKG], max([CAP]) as [CAP]
from yourtable
group by [TKG]
) as y2 on y2.[TKG] = y.[TKG] and y2.[CAP] = y.[CAP]
group by y.[TKG]
)
sql fiddle demo
Considering myself lucky that I don't work in SQLite often :)