Selecting the Highest Seq Number by nested Joining - sql-server

I would like to take biggest sequence number for each client Id (biggest sequence number will be calculated based on highest bank account balance).
This table has 100000 records.
Tables
ClientSeqTable T1
ClID SeqId
1 11
1 12
1 13
1 14
1 15
2 16
2 17
2 18
2 19
3 110
3 111
3 112
3 113
SeqBranchTable T2
SeqId BalID
11 1
12 2
13 3
14 4
15 5
16 6
17 7
18 8
19 9
110 10
111 11
112 12
113 13
Balancetable t3
BalID Balance
1 30000
2 26789
3 23456
4 12345
5 21234
6 12456
7 45632
8 23456
9 99999
10 12345
11 21234
12 12456
13 45632
Result would be
ClID SeqID Balance
1 1 30000
2 9 99999
3 4 45632
I have tried in this way but didn't work for me
SELECT RS.Investigationid,MAX(stt.sequenceid) 'SeqId', T.HighestBalance 'Balance'
FROM ClientSeqTable T1, SeqBranchTable T2, branbaltable t3,
( SELECT t1.clid ,MAX(T3.Balance) 'HighestBalance'
FROM ClientSeqTable T1, SeqBranchTable T2, branbaltable t3,
WHERE t1.seqid = T2.seqID
AND T2. balId= T3. balId
GROUP BY RS.Investigationid,stt.SequenceId
) T
WHERE T2.balId = T3.BalId
AND T1.SeqId = T2.SeqId
AND T3.HighestBalance = T2.balance
AND T1.clID = t.ClID
GROUP BY T1.ClID
With the above Query results are as below.
ClID SeqNu Bal
1 1 30000
1 2 30000
1 3 30000
1 4 30000
1 5 30000
2 3 99999
2 4 99999
2 1 99999
2 9 99999
3 2 45632
3 5 45632
3 3 45632
3 4 45632

If your able to use row_number function then should work:
select
*
from
(
select
t1.ClID, t1.SeqId, t3.Bal,
RowNumber = row_number() over (PARTITION BY t1.ClID order by t3.bal desc)
from
ClientSeqTable t1
inner join
SeqBranchTable t2 on t2.SeqId = t1.SeqId
inner join
Balancetable t3 on t3.BalID = t2.BalID
) t
where
t.RowNumber = 1
The important bit is row number partition by client id and then order by balance descending.

If you wanted to get your In-line on MAX you could do it this way
SELECT t1.ClID,
t1.SeqId,
t3.Balance
FROM ClientSeqTable t1
INNER JOIN SeqBranchTable t2
ON t2.SeqId = t1.SeqId
INNER JOIN Balancetable t3
ON t3.BalID = t2.BalID
INNER JOIN (SELECT Max(Balance) Bal,
t1.ClID
FROM ClientSeqTable t1
INNER JOIN SeqBranchTable t2
ON t2.SeqId = t1.SeqId
INNER JOIN Balancetable t3
ON t3.BalID = t2.BalID
GROUP BY t1.ClID) max_bal
ON t1.ClID = max_bal.ClID
AND t3.Balance = max_bal.bal
DEMO
But you should note this is not actually equivalent to using row_number (mouters solution). This may return multiple rows per ClID if there's a tie for max(balance). If you need that way of handling ties and you wanted to use a window function you could use RANK.

Related

Inner Joining select statements to find next record by date

I am stuck on trying to work out how to Inner Join a select statement to another select statement in order to return the next value for a specific item in date order. I have a number of tables that identify a race meeting, race and race entrant and an initial select that identifies a participant who wins their first race. Each race meeting contains multiple races and each race contains multiple entrants. I am using the participant unique identifier HorsePK in this instance to identify the records I need to return. What I am then trying to achieve is to identify their result at their next race and the race after that but not anu subsequent races that may occur. There will also be instances where the participant has only completed one race or 2 races and therefore these records should be excluded.
The initial select statement is:
Select RaceDate, HorsePK, HorseName, CareerRuns, FinishResult As ResultA
FROM [Punting].[dbo].[tblRace]
Inner Join tblRaceEntrant On tblRace.RacePK = tblRaceEntrant.RaceFK
Inner Join tblRaceMeeting On tblRace.RaceMeetingFK = tblRaceMeeting.RaceMeetingPK
Inner Join tblHorse On tblRaceEntrant.HorseFK = tblHorse.HorsePK
Where CareerRuns < 1 And FinishResult = 1
This works fine and returns the records I expect. My problem comes when I try to perform an inner join on a second statement and I think the problem is because I only want the next record for this participant in date order. I think the Syntax is meant to be similar to:
Select RaceDate, HorsePK, HorseName, CareerRuns, FinishResult As ResultA, ResultB
FROM [Punting].[dbo].[tblRace] t
Inner Join tblRaceEntrant On t.RacePK = tblRaceEntrant.RaceFK
Inner Join tblRaceMeeting On t.RaceMeetingFK = tblRaceMeeting.RaceMeetingPK
Inner Join tblHorse On tblRaceEntrant.HorseFK = tblHorse.HorsePK
Inner Join (Select Top (1) FinishResult As ResultB
FROM [Punting].[dbo].[tblRace] t1
Inner Join tblRaceEntrant On t1.RacePK = tblRaceEntrant.RaceFK
Inner Join tblRaceMeeting On t1.RaceMeetingFK = tblRaceMeeting.RaceMeetingPK
Inner Join tblHorse On tblRaceEntrant.HorseFK = tblHorse.HorsePK
Order By RaceDate Desc) On t.HorsePK = t1.HorsePK
Where CareerRuns < 1 And FinishResult = 1
This returns the error 'Incorrect syntax near the keyword 'On'.' and references 'Order By RaceDate Desc) On t.HorsePK = t1.HorsePK'. I really don't know why this is wrong or if it would even return the record that I am expecting, and this is where I need some assistance.
To compound this, I think I need to add another inner join to the nested inner join to get the third row for this participant also. The final output I am trying to achieve would look something like:
RaceDate,HorsePK,HorseName,CareerRuns,ResultA,ResultB,ResultC
2017-03-12,52352,Just Hifalutin,0,1,4,2
2018-01-02,52837,Daunting Duchess,0,1,1,8
2017-07-16,53319,Yurilla,0,1,9,3
2017-04-25,53427,Maria Elisa,0,1,4,1
I'm not particularly proficient in SQL server (obviously) but I believe this is a better method of returning these results than using cursors (which I know of but am not proficient in). Is there another way that I should be doing this?
Rather than pasting the DDL for each of the tables involved as it is quite a bit of data, these are the edited versions of the tables where the horse ID is used:
CREATE TABLE [dbo].[tblHorse](
[HorsePK] [int] IDENTITY(1,1) NOT NULL,
[HorseName] [nvarchar](250) NOT NULL,
[SireFK] [int] NULL,
[DamFK] [int] NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[tblRaceEntrant](
[RaceEntrantPK] [int] IDENTITY(1,1) NOT NULL,
[RaceFK] [int] NOT NULL,
[EntrantNumber] [int] NOT NULL,
[HorseFK] [int] NOT NULL,
[Age] [int] NULL,
[Gender] [varchar](5) NULL,
[FinishResult] [int] NULL
) ON [PRIMARY]
Sample data for tblHorse looks like:
HorsePK HorseName SireFK DamFK
77447 Scorpius 739 15383
84803 One Job 777 633
84815 Hooroo Lads 132 9797
84841 Ingear 766 21204
84884 Platinum Euros 143 11723
84889 Cryptic Wonder 211 17758
84912 Tricky Gal 90 19918
108448 Grey Detective 278 17515
109291 Nostradam Man 1347 6955
109319 Piccadilly Waltz 9 29848
Sample code for tblRaceEntrant looks like:
RaceEntrantPK RaceFK EntrantNumber HorseFK Age Gender FinishResult
67 10635 14 77447 2 C 1
355 27 8 84803 2 F 1
694 66 8 84841 2 F 1
845 82 8 84815 2 G 1
1342 129 3 84884 2 G 1
1841 179 8 84889 2 G 1
2082 203 6 84912 3 M 1
5163 510 7 84841 2 F 3
5236 517 2 84815 2 G 10
8574 871 3 84889 2 G 2
10062 1026 1 84912 3 M 1
27640 2824 3 84912 4 M 2
36037 3673 5 84912 4 M 1
42829 4401 7 84912 4 M 1
49460 5110 1 84912 4 M 2
60466 6290 8 84841 3 F 14
62017 6453 11 77447 3 C 2
67086 6975 18 84841 3 F 8
71604 7450 10 77447 3 C 1
76138 7921 7 84841 3 F 5
77838 8102 1 77447 3 C 4
84153 8761 4 84841 3 F 2
85015 8843 4 77447 3 C 5
114210 11756 6 77447 2 C 7
505957 52335 10 84841 3 F 3
508693 52635 3 84889 3 G 1
511758 52943 15 84841 3 F 1
516101 53391 8 84884 3 G 1
518339 53625 1 84889 3 G 2
521441 53947 12 84841 3 F 3
537301 55557 4 84912 4 M 1
545700 56358 2 84912 4 M 6
561458 59583 11 84912 4 M 3
569822 60358 2 77447 3 G 2
572503 60587 4 84912 4 M 2
575946 60853 9 77447 3 G 8
580109 61296 9 77447 3 G 3
580253 61310 9 84912 4 M 7
587297 61953 6 77447 3 G 5
603412 63355 3 77447 4 G 10
608617 63805 9 84841 4 M 2
615265 64429 4 77447 4 G 2
618260 64741 3 77447 4 G 5
623080 65235 3 84912 5 M 1
625750 65507 3 108448 3 C 1
630404 65993 3 84912 5 M 5
635248 66478 4 109291 3 G 1
635604 66517 7 109319 3 0 1
635652 66522 7 108448 3 C 9
637189 66679 10 84912 5 M 5
638846 66857 5 109291 3 G 10
I tried modifying the outer select to Select t.HorsePK instead of Select HorsePK as suggested, but this did not resolve the error.
you need to alias your subquery ("tx" in my example) and then join using this alias. Also since you want to join on t1.HorsePK you need to select it in the subquery.
Select RaceDate, HorsePK, HorseName, CareerRuns, FinishResult As ResultA, ResultB
FROM [Punting].[dbo].[tblRace] t
Inner Join tblRaceEntrant On t.RacePK = tblRaceEntrant.RaceFK
Inner Join tblRaceMeeting On t.RaceMeetingFK = tblRaceMeeting.RaceMeetingPK
Inner Join tblHorse On tblRaceEntrant.HorseFK = tblHorse.HorsePK
Inner Join (Select Top (1) FinishResult As ResultB, t1.HorsePK /* <-- select anything you need outside of this subquery */
FROM [Punting].[dbo].[tblRace] t1
Inner Join tblRaceEntrant On t1.RacePK = tblRaceEntrant.RaceFK
Inner Join tblRaceMeeting On t1.RaceMeetingFK = tblRaceMeeting.RaceMeetingPK
Inner Join tblHorse On tblRaceEntrant.HorseFK = tblHorse.HorsePK
Order By RaceDate Desc) tx On t.HorsePK = tx.HorsePK /* <-- Give an alias to you subquery and join on this alias*/
Where CareerRuns < 1 And FinishResult = 1

How to sum a column in SQL Server recursive cte for optimization?

I have following table with hierarchical data:
FolderId ParentFolderId NumberOfAffectedItems
---------------------------------------------
1 NULL 2
2 1 3
3 2 5
4 2 3
5 1 0
I want to find number of affected items under each folders and all of its children. I can write a recursive cte, which can produce following result, after that by doing group by I can find out what I want.
Normal recursive CTE:
WITH FolderTree AS
(
SELECT
fsa.FolderId AS ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
UNION ALL
SELECT
ft.ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.ParentFolderId = ft.ChildFolderId
)
Result:
ParentFolderId ChildFolderId NumberOfAffectedItems
--------------------------------------------------
1 1 2
1 2 3
1 3 5
1 4 3
1 5 0
2 2 3
2 3 5
2 4 3
3 3 5
4 4 3
5 5 0
But I want to optimize it, I want to start from the leaf child, while
moving through the CTE itself, I want to compute NumberOfAffectedItems.
Expected CTE
WITH FolderTree AS
(
SELECT
fsa.FolderId AS LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
LEFT JOIN
FoldersWithNumberOfReportsAffected f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT
ft.LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected + ft.NumberOfReportsAffected AS [ComputedResult]
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.FolderId = ft.ParentFolderId
)
Result:
LeafChildId ParentFolderId ComputedNumberOfAffectedItems
---------------------------------------------------------
3 3 5
3 2 8
3 1 10
4 4 3
4 2 5
4 1 7
5 5 0
5 1 2
If I group by ParentFolderId, I will get a wrong result, the reason is while doing computing in CTE, the same parent folder is visited from multiple
children, hence results in a wrong result. I want to find out is there anyway we can compute the result while going through the CTE itself.
Please check the following solution. I used your cte as basis and added the calculation (as column x) to it:
DECLARE #t TABLE(
FolderID INT
,ParentFolderID INT
,NumberOfAffectedItems INT
);
INSERT INTO #t VALUES (1 ,NULL ,2)
,(2 ,1 ,3)
,(3 ,2 ,5)
,(4 ,2 ,3)
,(5 ,1 ,0);
WITH FolderTree AS
(
SELECT 1lvl,
fsa.FolderId AS LeafChildId,
fsa.ParentFolderId AS ParentFolderId,
fsa.NumberOfAffectedItems
FROM
#t fsa
LEFT JOIN
#t f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT lvl + 1,
ft.LeafChildId,
fsa.ParentFolderId,
fsa.NumberOfAffectedItems
FROM
FolderTree ft
INNER JOIN #t fsa
ON fsa.FolderId = ft.ParentFolderId
)
SELECT LeafChildId,
ISNULL(ParentFolderId, LeafChildId) ParentFolderId,
NumberOfAffectedItems,
SUM(NumberOfAffectedItems) OVER (PARTITION BY LeafChildId ORDER BY ISNULL(ParentFolderId, LeafChildId) DESC) AS x
FROM FolderTree
ORDER BY 1, 2 DESC
OPTION (MAXRECURSION 0)
Result:
LeafChildId ParentFolderId NumberOfAffectedItems x
3 3 2 2
3 2 5 7
3 1 3 10
4 4 2 2
4 2 3 5
4 1 3 8
5 5 2 2
5 1 0 2

Get Unmatched records from the 3 table

I have 3 tables. The first table 'Status_Mapping' has following columns
Status_original Status_Site
accepted Call Verified
duplicate Duplicate Leads
dq DQ
'Lead_transaction' has the columns:
Lead_transaction_id Rate Status
11 0.01 accepted
12 0.02 accepted
13 0.01 newstatus
'Lead_Instance' table:
Lead_Instance_id Lead_transaction_id product_id affiliate_id
1 11 6 10
2 12 7 11
3 13 6 10
What I want to do is get the count(lead_instance_id) and sum(rate) for status which are not present in status_mapping table and should display status as "other", with product_id = 6 and affiliate_id = 10 My End result should be like
Total Sum Status
1 0.01 Other
you can start with this query:
select count(distinct a.Lead_Instance_id), sum(b.Rate)
from
Lead_Instance as a
inner join
Lead_transaction as b
on (a.Lead_transaction_id = b.Lead_transaction_id)
where
b.Status not in (select distinct Status_original from Status_Mapping)
and a.product_id = 6
and a.affiliate_id = 10

Select top N with joins

I am looking to join 2 tables with top n results of other table as explained below.
OrderHeader
OH_Id OrderDate
----------------------
1 2014-06-01
2 2014-06-02
3 2014-06-03
4 2014-06-04
5 2014-06-05
OrderProducts
OP_Id OH_Id Quantity
------------------------------
1 1 1
2 1 2
3 2 1
4 3 3
5 4 4
6 4 1
7 4 2
8 5 2
9 5 1
I am expecting result something like this for top 3 orders (4 rows).
OH_Id OrderDate Op_Id Quantity
------------------------------------------------
1 2014-06-01 1 1
1 2014-06-01 2 2
2 2014-06-02 3 1
3 2014-06-03 4 3
Note: I am looking specifically to join 2 tables rather writing as SP or looped queries.
select top 3 o.oh_id, o.orderdate, oo.op_id, oo.quantity
from orderheader o
join orderproducts oo on o.oh_id = oo.oh_id
If you want the first 3 order numbers from OrderHeader with all corresponding rows from OrderProducts try this.
select o.oh_id
,o.orderdate
,oo.op_id
,oo.quantity
from (SELECT TOP 3 *
FROM orderheader
ORDER BY OH_ID --or Date etc...
) o
INNER JOIN orderproducts oo
on o.oh_id = oo.oh_id
I think your description is confusing. You don't want top 3 as that will return only 3 rows. You just want ids 1-3 from what it sounds like.
SELECT *
FROM OrderHeader a
JOIN OrderHeader b on a.oh_id = b.oh_id
WHERE a.oh_id <= 3
you have to use a sub query like this
SELECT * FROM OrderHeader
INNER JOIN OrderProducts ON OrderHeader.OH_Id = OrderProducts.OH_Id
WHERE OrderHeader.OH_Id IN (SELECT TOP 3 OH_Id FROM OrderHeader)
A test sql fiddle is here
hope this helps

Select Distinct Sum SQL Server

I have a problem with the SUM(tblReview.GradePoint) I get 6 as result for GroupID Ballon because I have three products with GroupID Ballon, but I want the result to be 2 because there is only one review with that groupID in tblReview, how can I do that?
SELECT Product.GroupID,
max(Product.ProductID) as ProductID,
max (Product.BrandID) as BrandID,
max (Product.Year) as Year,
max (Product.Name) as Name,
max (tblBrand.BrandName)as BrandName,
SUM(tblReview.GradePoint) as GradePoint
FROM Product INNER JOIN
tblBrand ON Product.BrandID = tblBrand.BrandID LEFT OUTER JOIN
tblReview ON Product.GroupID = tblReview.GroupID
GROUP BY Product.GroupID
HAVING COUNT(distinct Product.GroupID) = 1
ORDER BY GradePoint DESC
Product
ProductID GroupID BrandID
--------------------------------------
1 Ballon 10
2 Ballon 10
3 Ballon 10
4 Ball 21
5 Ball 21
6 Chess 2
7 Chess 2
8 Hat 30
tblReview
ProductID GroupID GradePoint
------------------------------------------
2 Ballon 2
4 Ball 1
5 Ball 1
5 Ball 1
6 Chess -1
8 Hat 1
tblBrand
BrandID ProductID
-----------------------
10 1
10 2
10 3
21 4
21 5
2 6
2 7
30 8
Try this:
SELECT Product.GroupID,
max(Product.ProductID) as ProductID,
max (Product.BrandID) as BrandID,
max (Product.Year) as Year,
max (Product.Name) as Name,
max (tblBrand.BrandName)as BrandName,
max(tblReview.GradePoint) as GradePoint
FROM Product INNER JOIN
tblBrand ON Product.BrandID = tblBrand.BrandID LEFT OUTER JOIN
(SELECT GroupID, SUM(GradePoint) GradePoint FROM tblReview GROUP BY GroupID) tblReview ON Product.GroupID = tblReview.GroupID
GROUP BY Product.GroupID

Resources