Write Sql script to fetch data in one to many relationship - sql

I want to write a sql script which fetches data from 2 tables one is parent and second is child table
Bid
BidId | Code | Date
1 | H | 2022-05-12
2 | B | 2022-05-13
BidResult
BidResultId | BidId | Emi
12 | 1 | 50
13 | 1 | 20
14 | 2 | 30
Bid and BidResult
i want fetch column Date,Code,BidId from Bid Table
and BidResultId, EMI from BidResult but want a another column of Minimum EMI
from above example i want to fetch for bidId 1
Code H,date 2022-05-12,BidResultId 12, Emi 50 and Min Emi between 50 and 20 which is 20
so i have written following query
Select B.BidId,BR.EMI As Installment,
(Select Min(BR.EMI ) from BidResult BR
Inner Join Bid B on B.BidId = BR.BidResultId
where B.BidId = 5) As MinInstallment,
B.Code,
BR.BidResultId,
CONVERT(DATE, B.Date) As BidDate
from Bid B
Inner Join BidResult BR On B.BidId = BR.BidId
where B.BidId= 5 and B.TypeId = 1
All Field are starightforward except the minimum EMI value from BidResult for that BidId
please check the query and suggest if any modifications

Solution 1: With group by
select BID, min(EMI) EMI
into #temp
from BIDResult
group by BID
select b.Date, b.Code, b.BidId, br.BidResultId, br.EMI
from BID b
inner join #temp on t.BID = b.BID
inner join BIDResult br on br.BID = t.BID and br.EMI = t.EMI
Solution 2: Without group by
select *, ROW_Number() over(PARTITION by BID order by EMI) RowNumber
into #temp
from BIDResult
select b.Date, b.Code, b.BidId, br.BidResultId, br.EMI
from BID b
inner join #temp t on t.BID = b.BID and t.RowNumber = 1

Related

SQL query doesnt return expected values

I have 3 tables. 1st table stores coil information, 2nd table store coil information in transport and 3rd stores reserved coils.
coils
ID
SERIAL
COLOR
MATERIAL
STATUS
1
12345
5
1
2
2
12346
4
1
3
3
12347
3
1
2
coils_in_transport
ID
SERIAL
COLOR
MATERIAL
STATUS
1
f34S5
5
1
2
2
A23GG6
4
1
3
3
ff2S147
3
1
2
reserved_coils
ID
NUMBER
QUANTITY
START
END
1
12345
25
2022-05-01
2023-05-01
3
12347
252
2022-01-01
2023-05-01
4
A23GG6
33
2022-04-01
2023-05-01
5
ff2S147
35
2022-08-01
2023-05-01
I need to write query that will get all reserved coils (reserved_coils) that has status 2 and for each coil I need to join tables for materials and colors
material
ID
NAME
1
color
ID
NAME
I wrote query but it doesn't show coils in transport that are reserved, here is what I tried
SELECT a.QUANTITY, a.START, a.END, b.name, m.name
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material b ON b.material = b.id
where b.status = 2 and c.status = 2
To get all coils and colis_in_transport you need to use UNION for SELECT statements for both tables, each filtered by status value, which should be equal to 2. Then you need to do a JOIN between reserved_coils and the result of UNION to filter out reserved_coils rows.
Your query would be like this
SELECT
r.quantity,
r.start,
r.[end],
c.serial,
material.name AS material,
color.name AS color
FROM reserved_coils r
JOIN (
SELECT * FROM coils WHERE status = 2
UNION
SELECT * FROM coils_in_transport WHERE status = 2
) c ON r.number = c.serial
LEFT JOIN material ON material.id = c.material
LEFT JOIN color ON color.id = c.color
Demo
If you want left join twice on same table, this might help
SELECT a.QUANTITY, a.START, a.[END], isnull(b.serial,c.serial) serial,isnull(c1.name,c2.name) color, isnull(m.name,n.name) material
FROM reserved_coils a
LEFT JOIN coils b ON a.number = b.serial
LEFT JOIN coils_in_transport c ON a.number = c.serial
LEFT JOIN material m ON b.material = m.id
LEFT JOIN material n ON c.material = n.id
LEFT JOIN color c1 on b.color=c1.id
LEFT JOIN color c2 on c.color=c2.id
where isnull(b.status,c.status) = 2
DB<>Fiddle

How to join only latest date values from another table and prevent duplication

I'm trying to lookup a unique value from table b and get it into table a.
Table b stores multiple values that are changing by date.
I would like to join but only getting the values with the latest date from table b.
Table a
Unique ID
1
2
Table b
Date Unique ID Price
01/01/2019 1 100
01/02/2019 1 101
01/03/2019 1 102
01/01/2019 2 90
01/02/2019 2 91
01/03/2019 2 92
Expected result
Unique ID Price Date
1 102 01/03/2019
2 92 01/03/2019
Appreciate your help!
Have a sub-query that returns each UniqueID together with its max date. IN that result.
select * from tablename
where (UniqueID, date) in (select UniqueID, max(date)
from tablename
group by UniqueID)
You want correlated subquery :
select b.*
from tableb b
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = b.UniqueID);
If you want to go with JOIN then you can do JOIN with subquery :
select a.UniqueID , b.Price, b.Date
from tablea a inner join
tableb b
on b.UniqueID = a.UniqueID
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = a.UniqueID);
A correlated subquery?
select b.*
from b
where b.date = (select max(b2.date) from b b2 where b2.unique_id = b.unique_id);

SQL Query Left Outer Join To Current Query

I have a query and I want to look up the values from other table as a reference but not mess up my current query results. I think I have to use a Outer Left Join, but not sure how to incorporate that with my current query.
My current query looks similar to this:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH,
d.color
FROM TableA a,
TableB b,
TableC c,
TableD d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date IS NULL OR c.number IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1
Now, that gives me a table of 50 results. 'TableContacts' has the look up value to my b.project_number. So say my table of 50 results, only 10 of them have b.project_number, I need the lookup values from 'TableContacts' to also show in my results, but I don't want that to affect my results and cut it down to 10, I still need my original 50 results, just with that additional information. Help?
Just add the CONTACTS table to your joins:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH,
d.color,
ct.lookup_value --<< this is from the CONTACTS table
FROM TableA a
JOIN TableB b ON b.primary_key = a.PROJECT_ID
JOIN TableC c ON c.primary_key = a.PROJECT_ID
JOIN TableD d ON b.primary_key = d.project_ID
LEFT JOIN contacts ct ON ct.some_column = b.project_Number --<< this is the outer join to the CONTACTS table
WHERE (c.date IS NULL OR c.number IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1
As you obfuscated your table and column names it's hard to guess how exactly the join condition on the CONTACTS table should look like.
You could use this approach:
Create a table with the results of your current query:
create table t1 as
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH_col,
d.color
FROM a,b,c,d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date_col IS NULL OR c.number_col IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1;
Use a union to get the desired results:
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, TableContacts.lookup_column
from t1, TableContacts
where t1.project_number = TableContacts.project_number
UNION
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, null
from t1 where t1.project_number is null;
Illustration by creating dummy data:
select * from a;
PRIMARY_KEY | PROJECT_ID | PHASE
1 100 Phase-1
2 200 Phase-2
3 300 Phase-3
4 400 Phase-4
5 500 Phase-5
select * from b;
PRIMARY_KEY | PROJECT_NUMBER
100 null
200 2000
300 3000
400 null
500 5000
select * from c;
PRIMARY_KEY | NUMBER_COL | LENGTH_COL | DATE_COL
100 null 99 null
200 null 99 null
300 null 99 null
400 null 99 null
500 null 99 null
select * from d;
PROJECT_ID | COLOR
100 black
200 red
300 blue
400 black
500 yellow
select * from TableContacts;
PROJECT_NUMBER | LOOKUP_COLUMN
1000 l-1000
2000 l-2000
3000 l-3000
4000 l-4000
5000 l-5000
Existing query in question returns this:
SELECT a.primary_key,
a.phase,
b.project_number,
c.LENGTH_col,
d.color
FROM a,b,c,d
WHERE c.primary_key = a.PROJECT_ID
AND b.primary_key = a.PROJECT_ID
AND b.primary_key = d.project_ID
AND (c.date_col IS NULL OR c.number_col IS NULL)
AND d.color IN ('black','red','blue')
ORDER BY 1;
PRIMARY_KEY | PHASE | PROJECT_NUMBER | LENGTH_COL | COLOR
1 Phase-1 null 99 black
2 Phase-2 2000 99 red
3 Phase-3 3000 99 blue
4 Phase-4 null 99 black
The goal is to populate the lookup_column where project_number is not null. Running the union query provided at start of answer:
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, TableContacts.lookup_column
from t1, TableContacts
where t1.project_number = TableContacts.project_number
UNION
select t1.primary_key, t1.phase, t1.project_number, t1.length_col, t1.color, null
from t1 where t1.project_number is null;
PRIMARY_KEY | PHASE | PROJECT_NUMBER | LENGTH_COL | COLOR | LOOKUP_COLUMN
1 Phase-1 null 99 black null
2 Phase-2 2000 99 red l-2000
3 Phase-3 3000 99 blue l-3000
4 Phase-4 null 99 black null

Last Record Of Each Group Using Multiple Joins In Sql Server

I Have 3 tables Customer, Bank and BankTransaction.
On My View I want to display each customer with their Balance in the bank account.
Here is my tables
Customer
Id Name
---------
1 John
2 Jack
Bank
Id CustomerId BankName
----------------------------------
1 1 HSBC
2 2 HSBC
BankTransaction
Id BankID MoneyIn MoneyOut Balance
---------------------------------------------
1 1 1000 0 1000
2 1 0 500 500
3 2 2000 0 2000
4 2 2000 0 4000
5 2 1000 0 5000
Now I want to Display following data view query
John 500
Jack 5000
Last Balance of each customer
Try this
SELECT A.Name,
Sum(C.MoneyIN) - Sum(C.MoneyOut) AS Balance
FROM #Customer A
JOIN #Bank B ON A.Id = B.id
JOIN #BankTransaction C ON B.Id = C.BankID
GROUP BY A.Name
Using Window function you can get the result. Try this.
;WITH cte
AS (SELECT Row_number() OVER (partition BY b.id ORDER BY a.id DESC) rn,
c.Name,
a.balance
FROM BankTransaction a
JOIN bank b ON a.BankID = b.Id
JOIN Customer c ON c.Id = b.CustomerId)
SELECT name, balance
FROM cte
WHERE rn = 1

Get the max value of a column from set of rows

I have a table like this
Table A:
Id Count
1 4
1 16
1 8
2 10
2 15
3 18
etc
Table B:
1 sample1.file
2 sample2.file
3 sample3.file
TABLE C:
Count fileNumber
16 1234
4 2345
15 3456
18 4567
and so on...
What I want is this
1 sample1.file 1234
2 sample2.file 3456
3 sample3.file 4567
To get the max value from table A I used
Select MAX (Count) from A where Id='1'
This works well but my problem is when combining data with another table.
When I join Table B and Table A, I need to get the MAX for all Ids and in my query I dont know what Id is.
This is my query
SELECT B.*,C.*
JOIN A on A.Id = B.ID
JOIN C on A.id = B.ID
WHERE (SELECT MAX(COUNT)
FROM A
WHERE Id = <what goes here????>)
To summarise, what I want is Values from Table B, FileNumber from Table c (where the count is Max for ID from table A).
UPDATE: COrrecting table C above. Looks like I need Table A.
I think this is the query you're looking for:
select b.*, c.filenumber from b
join (
select id, max(count) as count from a
group by id
) as NewA on b.id = NewA.id
join c on NewA.count = c.count
However, you should take into account that I don't get why for id=1 in tableA you choose the 16 to match against table C (which is the max) and for id=2 in tableA you choose the 10 to match against table C (which is the min). I assumed you meant the max in both cases.
Edit:
I see you've updated tableA data. The query results in this, given the previous data:
+----+---------------+------------+
| ID | FILENAME | FILENUMBER |
+----+---------------+------------+
| 1 | sample1.file | 1234 |
| 2 | sample2.file | 3456 |
| 3 | sample3.file | 4567 |
+----+---------------+------------+
Here is a working example
Using Mosty’s working example (renaming the keyword count to cnt for a column name), this is another approach:
with abc as (
select
a.id,
a.cnt,
rank() over (
partition by a.id
order by cnt desc
) as rk,
b.filename
from a join b on a.id = b.id
)
select
abc.id, abc.filename, c.filenumber
from abc join c
on c.cnt = abc.cnt
where rk = 1;
select
PreMax.ID,
B.FileName,
C2.FileNumber
from
( select C.id, max( C.count ) maxPerID
from TableC C
group by C.ID
order by C.ID ) PreMax
JOIN TableC C2
on PreMax.ID = C2.ID
AND PreMax.maxPerID = C2.Count
JOIN TableB B
on PreMax.ID = B.ID