sql - getting the id from a row based on a group by - sql

Table A
tableAID
tableBID
grade
Table B
tableBID
name
description
Table A links to Table b from the tableBID found in both tables.
If I want to find the row in Table A, which has the highest grade, for each row in Table B, I would write my query like this:
select max(grade) from TableA group by tableBID
However, I don't just want the grade, I want the grade plus id of that row.

You could try something like
SELECT a.*
FROM TableA a INNER JOIN
(
SELECT tableBID,
MAX(grade) MaxGrade
FROM TableA
GROUP BY tableBID
) B ON a.tableBID = B.tableBID AND a.grade = B.MaxGrade
Using the Sql Server 2005 ROW_NUMBER function you could also try
SELECT tableAID,
tableBID,
grade
FROM (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY tableBID ORDER BY grade DESC) RowNum
FROM #TableA
) A
WHERE a.RowNum = 1

Assuming you will only have one Max() (HUGE ASSUMPTION) you can do min(tableaid) where grade = (select max(grade) etc....)
or if you want all matching ids
SELECT TableAID, Grade
FROM TableA INNER JOIN (SELECT tableBID,
MAX(grade) Grade
FROM TableA
GROUP BY tableBID) MaxGrade
ON TableA.Grade = MaxGrade.Grade

Just use a little self-referencing NOT EXISTS clause:
DECLARE #tableA TABLE (tableAID int IDENTITY(1,1), tableBID int, grade int)
INSERT INTO #tableA(tableBID, grade) VALUES(10, 1)
INSERT INTO #tableA(tableBID, grade) VALUES(10, 3)
INSERT INTO #tableA(tableBID, grade) VALUES(20, 4)
INSERT INTO #tableA(tableBID, grade) VALUES(20, 8)
INSERT INTO #tableA(tableBID, grade) VALUES(30, 10)
INSERT INTO #tableA(tableBID, grade) VALUES(30, 6)
SELECT tableAID, grade
FROM #tableA ta
WHERE NOT EXISTS (SELECT 1 FROM #tableA WHERE tableBID = ta.tableBID AND grade > ta.grade)

Related

Join and select column with max value

I am working on two tables in Oracle, TABLE_A containing unique IDs and Balance (number). TABLE_B shows, for the same IDs, the specific transactions and contains the following fields: IDs (not unique), BAL, Sequence_number.
I want to check that TABLE_A.Balance is always equal to TABLE_B.Balance having Max(Sequence_number).
So I expect to have just one row for each ID.
I've tried the following, yet it does not return a unique row for each ID but multiples. Why is that?
Select a.ID, a.Balance,b.Balance, b.sequence_number From TABLE_A a Inner join (select ID, Balance, max(sequence_number) as sequence_number from TABLE_B group by ID, Balance) b On a.ID = B.ID Group by a.ID, a.Balance, b.Balance, b.sequence_number
TABLE_A
ID_______Balance
1_______10
2_______15
3_______50
TABLE_B
ID____Balance____Sequence_number
1_______19_______1
1_______75_______2
1_______10_______3
2_______39_______1
2_______15_______2
3_______120_______1
3_______89_______2
3_______57_______3
3_______50_______4
You can use window functions:
select a.*, b.balance
from a left join
(select b.*,
row_number() over (partition by id order by sequence_number desc) as seqnum
from b
) b
on b.id = a.id and b.seqnum = 1;
I'm not quite sure what you want to compare, but this returns every row in a with the row in b that has the highest sequence number.
You can use row_number()over() window function to get the row having ID wise highest sequence_number.
Schema:
create table TABLE_A(ID int, Balance int);
insert into TABLE_A values(1,10);
insert into TABLE_A values(2,15);
insert into TABLE_A values(3,50);
create table TABLE_B (ID int , Balance int,Sequence_number int);
insert into TABLE_B values(1,19,1);
insert into TABLE_B values(1,75,2);
insert into TABLE_B values(1,10,3);
insert into TABLE_B values(2,39,1);
insert into TABLE_B values(2,15,2);
insert into TABLE_B values(3,120,1);
insert into TABLE_B values(3,89,2);
insert into TABLE_B values(3,57,3);
insert into TABLE_B values(3,50,4);
GO
Query:
with cte as
(
select id, balance, sequence_number, row_number()over (partition by id order by sequence_number desc)rnk from table_b
)
Select a.ID, a.Balance,b.Balance, b.sequence_number From TABLE_A a
Inner join cte b on a.id=b.id and rnk=1;
GO
Output:
ID
Balance
Balance
sequence_number
1
10
10
3
2
15
15
2
3
50
50
4
db<>fiddle here

Oracle ALL on SUBQUERY

I have simple question about Corelated Sub-Query:
The tables and data is as follows :
CREATE TABLE AUTHORS
(
NAME VARCHAR2(10 BYTE)
);
Insert into AUTHORS Values ('john');
Insert into AUTHORS Values ('bill');
Insert into AUTHORS Values ('dave');
CREATE TABLE BOOKS
(
NAME VARCHAR2(10 BYTE),
PRICE INTEGER
);
Insert into BOOKS Values ('john', 101);
Insert into BOOKS Values ('john', 200);
Insert into BOOKS Values ('john', 300);
insert into books values ('bill', 200 );
Insert into BOOKS Values ('bill', 10);
Insert into BOOKS Values ('dave', 5);
COMMIT;
Question: here 'john' has all books with price > 100.
But when I use following query, only one row is returned:
select * from
authors a
where 100 < all( select price from books b where a.nAME = b.NAME );
If you want to get all the matched records with books table with given condition then below query will work
select * from
authors a join books c on a.name=c.name
where 100 < all( select price from books b where a.nAME = b.NAME );
If you want all the books for names, where the minimum price is greater than 100, I would simply do:
select b.*
from (select b.*, min(b.price) over (partition by b.name) as minprice
from books b
) b
where minprice > 100;
If you only wanted the name, I would use aggregation:
select b.name
from books b
group by b.name
having min(b.price) > 100;
Both of these seem simpler than your approach.
If you are asking to return all books for John where price is > 100 then this should do it.
SELECT *
FROM authors a
INNER JOIN books b ON a.name = b.name
WHERE a.name = 'john' AND b.price > 100;

How to use a bunch of clause in a having statement. Oracle

assume i have a query like this:
SELECT table1.id
FROM (
SELECT id, sum(column) as A
FROM table1
GROUP BY id
) a1
Left join (
SELECT id,
sum(column) as B
FROM table 2
GROUP BY Id
) a2
on table1.id=table2.id
.
.
.
.
Left join (
SELECT id, sum(column) as G
FROM table 7
GROUP BY id
) g1
on table1.id=table7.id
Having or where A+B - (C+D+E+F+G) >0
I tried both, none works.
Having return error on there's no group by in the first select and where doesn't return any rows.
First your question have some issues.
I'm going to guess you mean put alias a, b, c, d ....
instead of a1, a2, g1.
Also your left join should be something like a.id = b.id at the moment you create a subquery you have to use the alias instead of tablename.
If you fix that you should add a WHERE, I also guess you mean use the SUM() result
WHERE a.A + b.B - (c.C+ d.D+ e.E+ f.F+ g.G) > 0
.
SELECT a.id
FROM (
SELECT id, sum(column) as sumA
FROM table1
GROUP BY id
) a
Left join
(
SELECT id, sum(column) as sumB
FROM table 2
GROUP BY Id
) b
on a.id = b.id
.
.
.
.
Left join
(
SELECT id, sum(column) as sumG
FROM table 2
GROUP BY id
) g
on f.id = g.id
WHERE a.sumA + b.sumB - (c.sumC + d.sumD + e.sumE + f.sumF + g.sumG) >0
Juan has the right answer. I am just adding a SQLFiddle to help strengthen his answer. Please look at a smaller instance of the same solution here: http://sqlfiddle.com/#!4/81c275/1
Tables
create table table1(id int, col int);
insert into table1 values (1, 10);
insert into table1 values (2, 20);
insert into table1 values (2, 30);
create table table2(id int, col int);
insert into table2 values (1, 5);
insert into table2 values (2, 3);
insert into table2 values (2, 2);
create table table3(id int, col int);
insert into table3 values (1, 100);
insert into table3 values (2, 20);
insert into table3 values (2, 3);
SQL
select a1.id
from (select id, sum(col) as A from table1 group by id) a1
left join (select id, sum(col) as B from table2 group by id) a2
on a1.id = a2.id
left join (select id, sum(col) as C from table3 group by id) a3
on a1.id = a3.id
where A + B - (C) > 0
You can add more tables in the SQLFiddle with whatever values you please, and change the SQL accordingly by appending D, E, F, G etc after C in (C).
The above example will result in output of 2 since ID 2's A+B = 55 and C = 23. A+B-C > 0 for this record and therefore the output will be 2.
I believe that you need to take out the 'where' and move it up if you still need it.
So that it would look something like this,
select table1.id from(
...
...
...)
Having ((A+B)-(C+D+R+F+G)>0)
According to this site:
http://www.w3schools.com/sql/sql_having.asp

Parent Child Query without using SubQuery

Let say I have two tables,
Table A
ID Name
-- ----
1 A
2 B
Table B
AID Date
-- ----
1 1/1/2000
1 1/2/2000
2 1/1/2005
2 1/2/2005
Now I need this result without using sub query,
ID Name Date
-- ---- ----
1 A 1/2/2000
2 B 1/2/2005
I know how to do this using sub query but I want to avoid using sub query for some reason?
If I got your meaning right and you need the latest date from TableB, then the query below should do it:
select a.id,a.name,max(b.date)
from TableA a
join TableB b on b.aid = a.id
group by a.id,a.name
SELECT a.ID, a.Name, MAX(B.Date)
FROM TableA A
INNER JOIN TableB B
ON B.ID = A.ID
GROUP BY A.id, A.name
It's a simple aggregation. Looks like you want the highest date per id/name combo.
create table #t1 (id int, Name varchar(10))
create table #t2 (Aid int, Dt date)
insert #t1 values (1, 'A'), (2, 'B')
insert #t2 values (1, '1/1/2000'), (1, '1/2/2000'), (2, '1/1/2005'), (2, '1/2/2005')
;WITH cte (AId, MDt)
as
(
select Aid, MAX(Dt) from #t2 group by AiD
)
select #t1.Id, #t1.Name, cte.MDt
from #t1
join cte
on cte.AId = #t1.Id

Join to only the "latest" record with t-sql

I've got two tables. Table "B" has a one to many relationship with Table "A", which means that there will be many records in table "B" for one record in table "A".
The records in table "B" are mainly differentiated by a date, I need to produce a resultset that includes the record in table "A" joined with only the latest record in table "B". For illustration purpose, here's a sample schema:
Table A
-------
ID
Table B
-------
ID
TableAID
RowDate
I'm having trouble formulating the query to give me the resultset I'm looking for any help would be greatly appreciated.
SELECT *
FROM tableA A
OUTER APPLY (SELECT TOP 1 *
FROM tableB B
WHERE A.ID = B.TableAID
ORDER BY B.RowDate DESC) as B
select a.*, bm.MaxRowDate
from (
select TableAID, max(RowDate) as MaxRowDate
from TableB
group by TableAID
) bm
inner join TableA a on bm.TableAID = a.ID
If you need more columns from TableB, do this:
select a.*, b.* --use explicit columns rather than * here
from (
select TableAID, max(RowDate) as MaxRowDate
from TableB
group by TableAID
) bm
inner join TableB b on bm.TableAID = b.TableAID
and bm.MaxRowDate = b.RowDate
inner join TableA a on bm.TableAID = a.ID
table B join is optional: it depends if there are other columns you want
SELECT
*
FROM
tableA A
JOIN
tableB B ON A.ID = B.TableAID
JOIN
(
SELECT Max(RowDate) AS MaxRowDate, TableAID
FROM tableB
GROUP BY TableAID
) foo ON B.TableAID = foo.TableAID AND B.RowDate= foo.MaxRowDate
With ABDateMap AS (
SELECT Max(RowDate) AS LastDate, TableAID FROM TableB GROUP BY TableAID
),
LatestBRow As (
SELECT MAX(ID) AS ID, TableAID FROM ABDateMap INNER JOIN TableB ON b.TableAID=a.ID AND b.RowDate = LastDate GROUP BY TableAID
)
SELECT columns
FROM TableA a
INNER JOIN LatestBRow m ON m.TableAID=a.ID
INNER JOIN TableB b on b.ID = m.ID
Just for the clarity's sake and to benefit those who will stumble upon this ancient question. The accepted answer would return duplicate rows if there are duplicate RowDate in Table B. A safer and more efficient way would be to utilize ROW_NUMBER():
Select a.*, b.* -- Use explicit column list rather than * here
From [Table A] a
Inner Join ( -- Use Left Join if the records missing from Table B are still required
Select *,
ROW_NUMBER() OVER (PARTITION BY TableAID ORDER BY RowDate DESC) As _RowNum
From [Table B]
) b
On b.TableAID = a.ID
Where b._RowNum = 1
Try using this:
BEGIN
DECLARE #TB1 AS TABLE (ID INT, NAME VARCHAR(30) )
DECLARE #TB2 AS TABLE (ID INT, ID_TB1 INT, PRICE DECIMAL(18,2))
INSERT INTO #TB1 (ID, NAME) VALUES (1, 'PRODUCT X')
INSERT INTO #TB1 (ID, NAME) VALUES (2, 'PRODUCT Y')
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (1, 1, 3.99)
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (2, 1, 4.99)
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (3, 1, 5.99)
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (1, 2, 0.99)
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (2, 2, 1.99)
INSERT INTO #TB2 (ID, ID_TB1, PRICE) VALUES (3, 2, 2.99)
SELECT A.ID, A.NAME, B.PRICE
FROM #TB1 A
INNER JOIN #TB2 B ON A.ID = B.ID_TB1 AND B.ID = (SELECT MAX(ID) FROM #TB2 WHERE ID_TB1 = A.ID)
END
This will fetch the latest record with JOIN. I think this will help someone
SELECT cmp.*, lr_entry.lr_no FROM
(SELECT * FROM lr_entry ORDER BY id DESC LIMIT 1)
lr_entry JOIN companies as cmp ON cmp.id = lr_entry.company_id