auto numbering for all the nodes and sub nodes of tree in SQL - sql

I want to have numbering and sub-numbering to tree using a SQL query.
I have tried multiple ways, I am new to SQL.
WITH tree AS
(
SELECT
c1.structureid, c1.parentid, c1.Text,
[level] = 1,
path = CAST(c1.structureid AS VARCHAR(100)),
pathindex = 0, numericalMapping = '0.0'
FROM
[ast].[Structure] c1
WHERE
c1.parentid IS NULL
UNION ALL
SELECT
c2.structureid, c2.parentid, c2.Text,
[level] = tree.[level] + 1,
Path = CAST(tree.path + '/' + RIGHT('000000000' + CAST(c2.structureid AS VARCHAR(10)), 10) AS VARCHAR(100)),
pathindex = 0, numericalMapping = '0.0'
FROM
[ast].[Structure] c2
INNER JOIN
tree ON tree.structureid = c2.parentid
)
SELECT
tree.level, tree.path, tree.parentid,
REPLICATE(' ', tree.level - 1) + tree.Text AS description,
C.* ,
RANK() OVER (PARTITION BY tree.parentId ORDER BY tree.parentId) AS indx
FROM
tree
INNER JOIN
[ast].[Value] AS C ON tree.structureid = C.structureid
ORDER BY
InstanceId, path
input Tables:
table 1
ValueId InstanceId StructureId ChoiceId Score
622 205 580 30 3
623 205 581 30 3
624 205 582 30 3
625 205 583 NULL NULL
626 205 584 NULL NULL
627 205 585 NULL NULL
628 205 586 NULL 5
629 205 587 NULL 5
630 205 588 NULL 5
631 205 589 40 4
632 205 590 NULL NULL
633 205 591 NULL NULL
table 2
StructureId AssessmentId ParentId Required Sequence Text Objective
580 127 NULL 1 0 Customer Satisfaction NULL
581 127 580 1 1 Top Customers NULL
582 127 580 1 1 Customer Feedback Process NULL
583 127 NULL 1 0 Continuous Improvement NULL
584 127 583 1 0 Gemba NULL
585 127 583 1 0 Real-Time Status NULL
586 127 583 -1 -1 TPM NULL
587 127 586 -1 0 Cleaning and Inspection NULL
588 127 586 1 1 Eliminate Contamination NULL
589 127 588 1 0 Test NULL
590 127 NULL 0 0 SAP Mii NULL
591 127 590 0 0 Dispatch Reports NULL
enter image description here
table 1
enter image description here
table 2
Note:
I want to have one more column which will tell the index of each record.
example : 1,2,3
if there are children in 1 then 1.01, 1.02 and so on

Related

Sum 2 column from different rows

I extract data from my table by use below query.
SELECT ID ,Desc_Cars ,DocID ,TabID
,(Select Dist1 where TabID = 85)
,(Select Dist2 where TabID = 86)
,(Select Days1 where TabID = 85)
,(Select Days2 where TabID = 85)
,(Select Days3 where TabID = 86)
FROM Details
where DocID = 16
I have following part of table in SQL:
ID
Desc_Cars
DocID
TabID
Dist1
Dist2
Days1
Days2
Days3
607
Car1
16
85
481
NULL
11
0
NULL
608 Car2
16
85
2072
NULL
21
2
NULL
609
Car3
16
85
333
NULL
15
6
NULL
610
Car4
16
85
1564
NULL
14
0
NULL
611
Car1
16
86
NULL
118
NULL
NULL
4
612
Car2
16
86
NULL
12
NULL
NULL
0
613
Car3
16
86
NULL
133
NULL
NULL
10
614
Car4
16
86
NULL
777
NULL
NULL
17
How can I SUM columns Dist1+Dist2 and Days1+Days2+Days3 to get that result
Desc_Cars
Sum_Dist
Sum_Days
Car1
599
15
Car2
2084
23
Car3
555
31
Car4
2341
31
I always operate on 1 DocID. Each DocID has always 2 tables: TabID 85 and 86
............................
Hi, the reason why I use Select in Select was that TabID 85 & 86 has values in other columns too
SELECT ID ,Desc_Cars ,DocID ,TabID
,Dist1
,Dist2
,Days1
,Days2
,Days3
FROM Details
where DocID = 16
ID
Desc_Cars
DocID
TabID
Dist1
Dist2
Days1
Days2
Days3
607
Car1
16
85
481
NULL
11
0
NULL
608
Car2
16
85
2072
NULL
21
2
NULL
609
Car3
16
85
333
NULL
15
6
NULL
610
Car4
16
85
1564
NULL
14
0
NULL
611
Car1
16
86
2129
118
10
2101
4
612
Car2
16
86
612
12
2
601
0
613
Car3
16
86
52
133
2
55
10
614
Car4
16
86
59
777
3
800
17
https://dbfiddle.uk/sAH7sv89
expected result, sum values like on picture:
Probably easiest to do with a self join:
select d1.Desc_Cars,
SUM(COALESCE(d1.Dist1, 0) + COALESCE(d2.Dist2, 0)) Sum_Dist,
SUM(COALESCE(d1.Days1, 0) + COALESCE(d1.Days2, 0) + COALESCE(d2.Days3, 0)) Sum_Days
from Details d1
join details d2
on d1.Desc_cars = d2.Desc_cars
and d1.tabid = d2.tabid-1
and d1.docid = d2.docid
where d1.DocID = 16
group by d1.Desc_Cars
Fiddle
#Jarlh:s version, letting the aggregate deal with nulls is more elegant in my opinion
select d1.Desc_Cars,
SUM(d1.Dist1) + SUM(d2.Dist2) Sum_Dist,
SUM(d1.Days1) + SUM(d1.Days2) + SUM(d2.Days3) Sum_Days
from Details d1
join details d2
on d1.Desc_cars = d2.Desc_cars
and d1.tabid = d2.tabid-1
and d1.docid = d2.docid
where d1.DocID = 16
group by d1.Desc_Cars
If tabid is not guaranteed to be consecutive, you can use row_number to match with next one:
with t (Desc_Cars, DocID, Dist1, Dist2, Days1, Days2, Days3, rn) AS (
select Desc_Cars, DocID, Dist1, Dist2, Days1, Days2, Days3
, row_number() over (partition by Desc_Cars, DocID order by tabid) as rn
from Details
)
select d1.Desc_Cars,
SUM(d1.Dist1) + SUM(d2.Dist2) Sum_Dist,
SUM(d1.Days1) + SUM(d1.Days2) + SUM(d2.Days3) Sum_Days
from t d1
join t d2
on d1.Desc_cars = d2.Desc_cars
and d1.rn = d2.rn-1
and d1.docid = d2.docid
group by d1.Desc_Cars;
Do a GROUP BY:
select Desc_Cars,
SUM(Dist1) + SUM(Dist2) Sum_Dist,
SUM(Days1) + SUM(Days2) + SUM(Days3) Sum_Days
from Details
where DocID = 16 -- <-- perhaps this condition is needed?
group by Desc_Cars

Get nearest date column value from another table in SQL Server

I have two tables A and B,
Table A
PstngDate WorkingDayOutput
12/1/2020 221
12/3/2020 327
12/4/2020 509
12/5/2020 418
12/7/2020 390
12/8/2020 431
12/9/2020 244
12/10/2020 246
12/11/2020 314
12/12/2020 301
12/14/2020 411
12/15/2020 530
12/16/2020 554
12/17/2020 300
12/18/2020 375
12/23/2020 402
12/24/2020 302
12/25/2020 269
12/26/2020 382
12/28/2020 608
Table B
PstngDate HolidayOutput isWorkingDay
12/2/2020 20 0
12/6/2020 24 0
12/13/2020 31 0
12/19/2020 82 0
12/22/2020 507 0
12/27/2020 537 0
Expected output:
PstngDate WorkingDayOutput HolidayOutput
12/1/2020 221 20
12/3/2020 327
12/4/2020 509
12/5/2020 418 24
12/7/2020 390
12/8/2020 431
12/9/2020 244
12/10/2020 246
12/11/2020 314
12/12/2020 301 31
12/14/2020 411
12/15/2020 530
12/16/2020 554
12/17/2020 300
12/18/2020 375 589
12/23/2020 402
12/24/2020 302
12/25/2020 269
12/26/2020 382 537
12/28/2020 608
I want to join TableB to TableA with nearest lesser date column. If you see Expectedoutput table, day 18 row of holidayoutput column is taking sum of day19 and day22 of table B.
I want to join TableB to TableA with nearest lesser date column
This sounds like a lateral join:
select a.*, coalesce(b.holidayquantity, 0) as holidayquantity
from a
outer apply (
select top (1) b.*
from b
where b.pstng_date >= a.pstng_date
order by b.pstng_date
) b
You can use self left join as follows:
Select pstng_date, workingDayQuantity,
HolidayQuantity,
workingDayQuantity + HolidayQuantity as total
From
(Select a.*, b.HolidayQuantity,
Row_number() over (partirion by a.psrng_date order by b.pstng_date) ad rn
From tablea a join tableb b On b.pstng_date > a.pstng_date) t
Where rn=1

Implement the Scalar Function inside a CTE

i have a View(The View contains a CTE inside it as shown below) where in I am calling one Scalar Function and in the same scalar function the view is called. This whole process making the performance slower. Can i implement the function's functionality in the same View.
Please help
WITH tree AS
(
SELECT c1.structureid,c1.assessmentid, c1.sequence,c1.Required,c1.Objective, c1.parentid, c1.Text, [level] = 1, path = cast( c1.structureid as varchar(100))
FROM [ast].[Structure] c1
WHERE c1.parentid IS NULL
UNION ALL
SELECT c2.structureid, c2.assessmentid, c2.sequence,c2.Required,c2.Objective, c2.parentid, c2.Text, [level] = tree.[level] + 1,
Path = Cast(tree.path+'/'+right('000000000' + cast(c2.structureid as varchar(10)),10) as varchar(100))
FROM [ast].[Structure] c2 INNER JOIN tree ON tree.structureid = c2.parentid
)
SELECT tree.level,tree.sequence,
tree.path, parentid, tree.assessmentid, tree.Required,tree.Objective, (SELECT [dbo].Tree_full_index(tree.structureid))+' '+ tree.Text AS description ,C.* ,
wasScored = (case when C.choiceid is null then 0 else 1 end ),
wasDerived = (case when C.choiceid is null and C.Score is not null then 1 else 0 end )
FROM tree inner join [ast].[Value] as C on tree.structureid = C.structureid
Scalar Function
ALTER FUNCTION [dbo].[Tree_full_index]
(
#tree_node_id int
)
RETURNS varchar(20)
AS
BEGIN
declare #result varchar(20)
set #result =''
declare #node_seq_index varchar(5)
DECLARE #parentID int
select #node_seq_index=isnull(sequence,''),#parentID=isnull(parentid,0) from vwAssesment where structureid=#tree_node_id
set #result=#node_seq_index
WHILE #parentID > 0
BEGIN
SELECT #tree_node_id = #parentID
select #node_seq_index=isnull(sequence,''),#parentID=parentid from vwAssesment where structureid=#tree_node_id
set #result=#node_seq_index+'.0'+#result
END
RETURN #result
END
Structure Table
StructureId AssessmentId ParentId Required Sequence Text Objective
633 132 NULL 1 1 Customer Satisfaction understand our top Customers and our supplier ranking with them.
634 132 633 1 1 Top Customers NULL
635 132 634 1 1 Display top Customers on Lead Board NULL
636 132 634 1 2 Display Customer Supplier Ranking for Facility - NA NULL
637 132 634 1 3 Display Work Plan that provides path to Preferred Supplier status NULL
638 132 633 1 2 Real Time Response Process NULL
639 132 638 0 1 Real-time response system in place when abnormalities occur with documented Counter Measures NULL
640 132 NULL 1 2 Continuous Improvement ensure driving foundation for Continuous Improvement
641 132 640 1 1 Gemba NULL
642 132 641 1 1 Routine and scheduled NULL
643 132 641 1 2 Incorporated into appropriate different levels of organization NULL
644 132 640 1 2 TPM NULL
645 132 644 1 1 Perform initial Cleaning & Inspection (Level 1) NULL
646 132 645 1 1 Learn how to identify equipment problems NULL
The result Should have the column with actual index of the Node as shown
level sequence parentid assessmentid Required Objective description ValueId InstanceId StructureId ChoiceId Score wasScored wasDerived
1 1 NULL 132 1 understand our top Customers and our supplier ranking with them. Ensure In-Station Quality and continuous improvement. 1 Customer Satisfaction 666 207 633 NULL 2 0 1
2 1 633 132 1 NULL 1.01 Top Customers 667 207 634 NULL 4 0 1
3 1 634 132 1 NULL 1.01.01 Display top Customers on Lead Board 668 207 635 40 4 1 0
3 2 634 132 1 NULL 1.01.02 Display Customer Supplier Ranking for Facility - NA 669 207 636 40 4 1 0
3 3 634 132 1 NULL 1.01.03 Display Work Plan that provides path to Preferred Supplier status 670 207 637 40 4 1 0
2 2 633 132 1 NULL 1.02 Real Time Response Process 671 207 638 NULL NULL 0 0
3 1 638 132 0 NULL 1.02.01 Real-time response system in place when abnormalities occur with documented Counter Measures 672 207 639 NULL NULL 0 0
1 2 NULL 132 1 ensure driving foundation for Continuous Improvement culture to be successful and achieve meaningful results 2 Continuous Improvement 673 207 640 NULL 3.5 0 1
2 1 640 132 1 NULL 2.01 Gemba 674 207 641 20 2 1 0
3 1 641 132 1 NULL 2.01.01 Routine and scheduled 675 207 642 NULL NULL 0 0
3 2 641 132 1 NULL 2.01.02 Incorporated into appropriate different levels of organization (Facility Manager, Staff, site Director) 676 207 643 NULL NULL 0 0
2 2 640 132 1 NULL 2.02 TPM 677 207 644 NULL 5 0 1
3 1 644 132 1 NULL 2.02.01 Perform initial Cleaning & Inspection (Level 1) 678 207 645 50 5 1 0
4 1 645 132 1 NULL 2.02.01.01 Learn how to identify equipment problems 679 207 646 NULL NULL 0 0
You can implement the function in the view or in a CTE before the tree cte, as below:-
;with prev as (
select *,1 [depth],cast(isnull([sequence],'') as varchar(max)) [Tree_full_index] From vwAssesment where parentid is null
union all
select v.*,prev.depth+1 [depth],+[Tree_full_index]+'.0'+isnull(v.[sequence],'') from prev
inner join vwAssesment v on v.parentid=prev.structureid
),Tree as (.......
I tested the prev cte, it will return the Tree_full_index as part of it with all columns of vwAssesment , so change your query to use prev instead of vwAssesment, or update vwAssesment or create a new view to have the Tree_full_index and use it
For the belowsample data:-
Declare #vwAssesment Table(
structureid int,
parentid int,
[sequence] varchar(5)
)
insert into #vwAssesment values(1,null,'1')
insert into #vwAssesment values(2,null,'2')
insert into #vwAssesment values(3,null,'3')
insert into #vwAssesment values(4,1, '1')
insert into #vwAssesment values(5,1, '2')
insert into #vwAssesment values(6,1, '3')
insert into #vwAssesment values(7,2, '2')
insert into #vwAssesment values(8,2, '3')
insert into #vwAssesment values(9,8, '2')
insert into #vwAssesment values(10,8,'3')
The result is:-
structureid parentid sequence depth Tree_full_index
1 NULL 1 1 1
2 NULL 2 1 2
3 NULL 3 1 3
4 1 1 2 1.01
5 1 2 2 1.02
6 1 3 2 1.03
7 2 2 2 2.02
8 2 3 2 2.03
9 8 2 3 2.03.02
10 8 3 3 2.03.03

How to find the row associated with the min/max of a column?

So basically I have some simple SQL code that looks like the following;
SELECT
[Column1]
,[Column2]
,[Column3]
,[Column4]
,MIN([Column5]) AS maxColumn5
,MAX([Column6]) AS minColumn6
,SUM([Column7]) AS sumColumn7
,SUM([Column8]) AS sumColumn8
,SUM([Column9]) AS sumColumn9
FROM
[tableName]
GROUP BY
[Column1]
,[Column2]
,[Column3]
,[Column4]
What I am trying to do is also find the column either 'Column1', 'Column2', or 'Column3' that corresponds to the MIN([Column6]) and then the column that corresponds to MAX([Column8]).
The output should be exactly the same except there will be an extra 2 column at the end specifying which one the min and max are associated with.
I think there is a simple problem in your question, as Col1,Col2,Col3 that correspond to the max or min, are displayed directly, in other words you have them as you are grouping by Col1,Col2,Col3 & Col4.
As you did not provide some data, I will set some random data to prove my point.
Lets create a memory table similar to yours with 9 columns and fill it with random data for col6-8 with 10 rows for example, you can use the below:-
Declare #data Table(
Column1 int,Column2 int,Column3 int,Column4 int,Column5 int,Column6 int,Column7 int,Column8 int,Column9 int
)
declare #index int=5
while(#index>0)
begin
insert into #data values(1,2,3,4,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000)
insert into #data values(5,6,7,8,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000)
set #index=#index-1
end
we can see the data with the below
select * from #data order BY [Column1],[Column2],[Column3],[Column4]
Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8 Column9
1 2 3 4 669 203 278 364 577
1 2 3 4 389 316 290 548 661
1 2 3 4 835 555 942 985 604
1 2 3 4 477 743 580 305 414
1 2 3 4 431 296 471 150 352
1 2 3 4 346 220 573 941 633
1 2 3 4 392 450 652 978 883
1 2 3 4 235 479 751 136 978
1 2 3 4 906 183 141 915 783
1 2 3 4 329 342 682 977 870
5 6 7 8 218 740 41 299 816
5 6 7 8 800 630 674 888 799
5 6 7 8 27 307 446 743 345
5 6 7 8 501 928 824 592 691
5 6 7 8 439 624 260 757 547
5 6 7 8 287 610 287 708 652
5 6 7 8 441 711 433 642 343
5 6 7 8 751 928 237 53 535
5 6 7 8 594 768 708 173 33
5 6 7 8 352 703 943 867 661
now lets see the result of your grouping that you provided without any change
Col1 Col2 Col3 Col4 minCol5 maxCol6 maxCol8 sumCol7 sumCol8 sumCol9
1 2 3 4 235 743 985 5360 6299 6755
5 6 7 8 27 928 888 4853 5722 5422
so if we go back to your question, what is the value of Col1,Col2,Col3 for the maxCol6, well for each maxCol6 you have the values of Col1,Col2,Col3 & even Col4.
so what are the values for Col1,Col2,Col3 for maxCol16 that is 928, well they are 5,6 & 7.
ok, now lets say you want the record key that have that maxCol6, that is easy too, we would add an identity col as ID as below:-
Declare #data Table(
ID int identity(1,1), Column1 int,Column2 int,Column3 int,Column4 int,Column5 int,Column6 int,Column7 int,Column8 int,Column9 int
)
declare #index int=10
while(#index>0)
begin
insert into #data values(1,2,3,4,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000)
insert into #data values(5,6,7,8,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000,RAND()*1000)
set #index=#index-1
end
select * from #data order BY [Column1],[Column2],[Column3],[Column4]
;with agg as (
SELECT
[Column1]
,[Column2]
,[Column3]
,[Column4]
,MIN([Column5]) AS minColumn5
,MAX([Column6]) AS maxColumn6
,MAX([Column8]) AS maxColumn8
,SUM([Column7]) AS sumColumn7
,SUM([Column8]) AS sumColumn8
,SUM([Column9]) AS sumColumn9
FROM
#data [tableName]
GROUP BY
[Column1]
,[Column2]
,[Column3]
,[Column4]
)
--select * from agg order BY [Column1],[Column2],[Column3],[Column4]
select agg.*,maxCol6.ID [MaxCol6Seq],maxCol8.ID [MaxCol8Seq] from agg
inner join #data maxCol6
on agg.Column1=maxCol6.Column1
and agg.Column2=maxCol6.Column2
and agg.Column3=maxCol6.Column3
and agg.Column4=maxCol6.Column4
and agg.maxColumn6=maxCol6.Column6
inner join #data maxCol8
on agg.Column1=maxCol8.Column1
and agg.Column2=maxCol8.Column2
and agg.Column3=maxCol8.Column3
and agg.Column4=maxCol8.Column4
and agg.maxColumn8=maxCol8.Column8
As this is a new run for this set of data , below:-
ID Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8 Column9
1 1 2 3 4 201 848 993 50 304
3 1 2 3 4 497 207 644 399 104
5 1 2 3 4 445 321 822 151 185
7 1 2 3 4 611 402 620 61 543
9 1 2 3 4 460 409 182 915 211
11 1 2 3 4 886 804 180 213 282
13 1 2 3 4 614 709 932 806 162
15 1 2 3 4 795 752 110 474 463
17 1 2 3 4 737 545 77 648 727
19 1 2 3 4 788 862 266 464 851
20 5 6 7 8 218 561 943 572 54
18 5 6 7 8 741 621 610 214 536
16 5 6 7 8 579 248 374 693 761
14 5 6 7 8 866 415 198 528 657
12 5 6 7 8 905 947 500 50 387
10 5 6 7 8 492 860 948 299 220
8 5 6 7 8 861 328 727 40 327
6 5 6 7 8 435 534 707 769 777
4 5 6 7 8 587 68 45 184 614
2 5 6 7 8 189 24 289 121 772
The result is as below:-
C1 C2 C3 C4 minC5 maxC6 maxC8 sumC7 sumC8 sumC9 MaxCol6Seq MaxCol8Seq
1 2 3 4 201 862 915 4826 4181 3832 19 9
5 6 7 8 189 947 769 5341 3470 5105 12 6
Hope this helps.
If you just want a flag on each row specifying whether the value is the overall maximum or minimum, you can use window functions and CASE:
SELECT [Column1], [Column2], [Column3], [Column4],
MAX([Column5]) AS maxColumn5,
MIN([Column6]) AS minColumn6,
SUM([Column7]) AS sumColumn7,
SUM([Column8]) AS sumColumn8,
SUM([Column9]) AS sumColumn9,
(CASE WHEN MIN([Column6]) = MIN(MIN([Column6])) OVER () THEN 1 ELSE 0 END) as is_min_column6,
(CASE WHEN MAX([Column7]) = MAX(MAX([Column7])) OVER () THEN 1 ELSE 0 END) as is_max_column7
FROM [tableName]
GROUP BY [Column1], [Column2], [Column3], [Column4]

HSQLDB query to replace a null value with a value derived from another record

This is a small excerpt from a much larger table, call it LOG:
RN EID FID FRID TID TFAID
1 364 509 7045 null 7452
2 364 509 7045 7452 null
3 364 509 7045 7457 null
4 375 512 4525 5442 5241
5 375 513 4525 5863 5241
6 375 515 4525 2542 5241
7 576 621 5632 null 5452
8 576 621 5632 2595 null
9 672 622 5632 null 5966
10 672 622 5632 2635 null
I would like a query that will replace the null in the 'TFAID' column with the value from the 'TFAID' column from the 'FID' column that matches.
Desired output would therefore be:
RN EID FID FRID TID TFAID
1 364 509 7045 null 7452
2 364 509 7045 7452 7452
3 364 509 7045 7457 7452
4 375 512 4525 5442 5241
5 375 513 4525 5863 5241
6 375 515 4525 2542 5241
7 576 621 5632 null 5452
8 576 621 5632 2595 5452
9 672 622 5632 null 5966
10 672 622 5632 2635 5966
I know that something like
SELECT RN,
EID,
FID,
FRID,
TID,
(COALESCE TFAID, {insert clever code here}) AS TFAID
FROM LOG
is what I need, but I can't for the life of me come up with the clever bit of SQL that will fill in the proper TFAID.
HSQLDB supports SQL features that can be used as alternatives. These features are not supported by some other databases.
CREATE TABLE LOG (RN INT, EID INT, FID INT, FRID INT, TID INT, TFAID INT);
-- using LATERAL
SELECT l.RN, l.EID, l.FID, l.FRID, l.TID,
COALESCE(l.TFAID, f.TFAID) AS TFAID
FROM LOG l , LATERAL (SELECT MAX(TFAID) AS TFAID FROM LOG f WHERE f.FID = l.FID) f
-- using scalar subquery
SELECT l.RN, l.EID, l.FID, l.FRID, l.TID,
COALESCE(l.TFAID, (SELECT MAX(TFAID) AS TFAID FROM LOG f WHERE f.FID = l.FID)) AS TFAID
FROM LOG l
Here is one approach. This aggregates the log to get the value and then joins the result in:
SELECT l.RN, l.EID, l.FID, l.FRID, l.TID,
COALESCE(l.TFAID, f.TFAID) AS TFAID
FROM LOG l join
(select fid, max(tfaid) as tfaid
from log
group by fid
) f
on l.fid = f.fid;
There may be other approaches that are more efficient. However, HSQL doesn't implement all SQL features.