Finding value with most common condition - sql

I am having a lot of trouble with PostgreSQL trying to figure out how to find the most common value that fits a specific criteria. The ID is the ID number of the book, meaning repeating numbers means there are multiple copies of the book.
I have 2 tables here:
Table A:
=====+===================
ID | Condition
-------------------------
1 | Taken
1 |
1 | Taken
1 |
2 | Taken
3 | Taken
3 |
3 | Taken
3 | Taken
4 |
4 | Taken
etc.
Table B:
=====+===================
ID | Name
-------------------------
1 | BookA
2 | BookB
3 | BookC
4 | BookD
etc.
What I need is to simply find which book has the most copies taken and simply print out the name of the book. In this case all I need is:
BookC
The problem is that I can't figure out how to find how much each individual ID has books taken. I tried using a temp table something like so:
CREATE TEMP TABLE MostCommon AS
(SELECT ID
FROM TableA
WHERE SUM(CASE WHEN Condition>0 then 1 else 0 END)
)
SELECT NAME FROM TableB, MostCommon WHERE
MostCommon.ID = TableB.ID;
But it either throws an error or simply doesn't give me what I need. Any help would be greatly appreciated.

Ok, so firstly I assumed that your columns and tables names are case sensitive which means you must use duble quote marks. To print most "taken" book name with number of "taken" copies, you can use simple aggragete count(), then order the output descending and at the end limit the output to 1 row, like:
SELECT
b."ID",
b."Name",
count(*) as takenCount
FROM "TableA" a
JOIN "TableB" b ON a."ID" = b."ID"
WHERE a."Condition" = 'Taken'
GROUP BY b."ID", b."Name"
ORDER BY 3 DESC
LIMIT 1;

CREATE TEMP TABLE MostCommon AS
(SELECT id, (sum(ID)/id) book_taken FROM tableA where condition = 'Taken' group by id);
select name from tableB t2 join MostCommon mc on mc.id = t2.id where mc.id in (select max(book_taken) from MostCommon)

To make the data sensible (i.e. no duplicate records), I have to change the schema a little.
CREATE TABLE book_condition (
created TIMESTAMP,
book_id INTEGER,
condition VARCHAR,
PRIMARY KEY (created, book_id));
INSERT INTO book_condition (created, book_id, condition)
VALUES
('2016-01-01 08:30', 1, 'Taken'),
('2016-01-01 08:35', 1, ''),
('2016-01-01 08:40', 1, 'Taken'),
('2016-01-01 08:45', 1, ''),
('2016-01-01 08:50', 2, 'Taken'),
('2016-01-01 08:55', 3, 'Taken'),
('2016-01-01 09:00', 3, ''),
('2016-01-01 09:05', 3, 'Taken'),
('2016-01-01 09:10', 3, 'Taken'),
('2016-01-01 09:15', 4, ''),
('2016-01-01 09:20', 4, 'Taken');
CREATE TABLE book (
book_id INTEGER,
name VARCHAR,
PRIMARY KEY (book_id));
INSERT INTO book (book_id, name)
VALUES
(1, 'BookA'),
(2, 'BookB'),
(3, 'BookC'),
(4, 'BookD');
Then, the question breaks down into:
How many copies of each book were ever taken?
SELECT
book_id,
COUNT(book_id) AS total_taken
FROM book_condition
WHERE
condition = 'Taken'
GROUP BY book_id
;
book_id | total_taken
---------+-------------
1 | 2
2 | 1
3 | 3
4 | 1
(4 rows)
How to rank records by total_taken value?
SELECT
book_id,
total_taken,
RANK() OVER (
ORDER BY total_taken DESC
) AS total_taken_rank
FROM (
SELECT
book_id,
COUNT(book_id) AS total_taken
FROM book_condition
WHERE
condition = 'Taken'
GROUP BY book_id
) AS bt
ORDER BY total_taken_rank ASC
;
book_id | total_taken | total_taken_rank
---------+-------------+------------------
3 | 3 | 1
1 | 2 | 2
2 | 1 | 3
4 | 1 | 3
(4 rows)
How to get the name of the book in a query result containing its key (id) value?
SELECT
b.book_id,
b.name,
bt.total_taken,
RANK() OVER (
ORDER BY bt.total_taken DESC
) AS total_taken_rank
FROM
book AS b
LEFT JOIN (
SELECT
book_id,
COUNT(book_id) AS total_taken
FROM book_condition
WHERE
condition = 'Taken'
GROUP BY book_id
) AS bt
USING (book_id)
ORDER BY
total_taken_rank ASC,
book_id ASC
;
book_id | name | total_taken | total_taken_rank
---------+-------+-------------+------------------
3 | BookC | 3 | 1
1 | BookA | 2 | 2
2 | BookB | 1 | 3
4 | BookD | 1 | 3
(4 rows)
How to get only the highest-ranking records in the result?
SELECT
br.book_id,
br.name,
br.total_taken
FROM (
SELECT
b.book_id,
b.name,
bt.total_taken,
RANK() OVER (
ORDER BY bt.total_taken DESC
) AS total_taken_rank
FROM
book AS b
LEFT JOIN (
SELECT
book_id,
COUNT(book_id) AS total_taken
FROM book_condition
WHERE
condition = 'Taken'
GROUP BY book_id
) AS bt
USING (book_id)
) AS br
WHERE
total_taken_rank = 1
;
book_id | name | total_taken
---------+-------+-------------
3 | BookC | 3
(1 row)

Related

Select all records of one table that contain two records in another with certain id

I have two tables of 1:m relation. Need to select which People records have both records in Actions table whit id 1 and 2
People
+----+------+--------------+
| id | name | phone_number |
+----+------+--------------+
| 1 | John | 111111111111 |
+----+------+--------------+
| 3 | Jane | 222222222222 |
+----+------+--------------+
| 4 | Jack | 333333333333 |
+----+------+--------------+
Action
+----+------+------------+
| id | PplId| ActionId |
+----+------+------------+
| 1 | 1 | 1 |
+----+------+------------+
| 2 | 1 | 2 |
+----+------+------------+
| 3 | 2 | 1 |
+----+------+------------+
| 4 | 4 | 2 |
+----+------+------------+
Output
+----+------+--------------+----------
|PplId| name | Phone |ActionId |
+-----+------+-------------+----+-----
| 1 | John | 111111111111| 1 |
+-----+------+-------------+----+-----
| 1 | John | 111111111111| 2 |
+-----+------+-------------+----+-----
Return records of People that have both Have Actionid 1 and Action id 2(Have records in Actions).
Window functions are one method. Assuming actions are not duplicated for a person:
select pa.*
from (select p.*, a.action, count(*) over (partition by p.id) as num_actions
from people p join
action a
on p.id = a.pplid
where a.action in (1, 2)
) pa
where num_actions = 2;
In my opinion, getting two rows with the action detail seems superfluous -- you already know the actions. If you only want the people, then exists comes to mind:
select p.*
from people p
where exists (select 1 from actions where a.pplid = p.id and a.action = 1) and
exists (select 1 from actions where a.pplid = p.id and a.action = 2);
With the right index (actions(pplid, action)), I would expect two exists to be faster than group by.
Try this below query using subquery and join
select a.Pplid, name, phone, actionid from (
select a.pplid as Pplid, name, phone_number as phone
from People P
join Action A on a.pplid= p.id
group by a.pplid, name, phone_number
having count(*)>1 )P
join Action A on a.Pplid= p.Pplid
Try something like this
IF OBJECT_ID('tempdb..#People') IS NOT NULL DROP TABLE #People
CREATE TABLE #People (id INT, name VARCHAR(255), phone_number VARCHAR(50))
INSERT #People
SELECT 1, 'John', '111111111111' UNION ALL
SELECT 3, 'Jane', '222222222222' UNION ALL
SELECT 4, 'Jack', '333333333333'
IF OBJECT_ID('tempdb..#Action') IS NOT NULL DROP TABLE #Action
CREATE TABLE #Action (id INT, PplId INT, ActionId INT)
INSERT #Action
SELECT 1, 1, 1 UNION ALL
SELECT 2, 1, 2 UNION ALL
SELECT 3, 2, 1 UNION ALL
SELECT 4, 4, 2
GO
SELECT p.ID AS PplId
, p.name
, p.phone_number AS Phone
, a.ActionId
FROM #People p
JOIN #Action a
ON p.ID = a.PplId
WHERE p.ID IN ( SELECT PplId
FROM #Action
WHERE ActionId IN (1, 2)
GROUP BY PplId
HAVING COUNT(*) = 2 )
AND a.ActionId IN (1, 2)
GO

SQL Server - select every combination

We have two tables below, I am trying to write a query that will select EVERY Purchase for EVERY person on the team. For example, it should show PersonA being associated to PurchaseID 1 and 2 because they are on the same Team as TeamA.
Is this possible? I thought a cross join would work but it seemed to bring back too many columns. I am running SQL Server.
Thank you
Purchases
| PurchaseID | PersonID |
|------------ |---------- |
| 1 | TeamA |
| 2 | TeamA |
| 3 | PersonA |
| 4 | PersonB |
| 5 | TeamB |
Teams
| TeamID | PersonID |
|-------- |---------- |
| 1 | PersonA |
| 1 | TeamA |
| 1 | PersonC |
| 2 | PersonB |
| 2 | TeamB |
Expected results (when filtered on PurchaseID 1):
| PurchaseID | PersonID |
|------------ |---------- |
| 1 | TeamA |
| 1 | PersonA |
| 1 | PersonC |
Your data structure is a little odd, but I think I understand what you want.
If PersonA made a purchase, and PersonA is on TeamA, then everyone on TeamA should be shown as being associated with the purchase, right? Like "I bought these doughnuts for my team, so everyone on my team gets a doughnut".
What you're going to want is to join Purchase to Team on PersonID, as you probably guessed. But then use a CROSS APPLY function, which is in inline table value function, to return all the people on the same team as the person in the "current row".
I used two common table expressions to represent your tables so I could run it. You'll just want the SELECT part:
with Purchases as (
select 1 as PurchaseID, 'TeamA' as PersonID
union select 2 as PurchaseID, 'TeamA' as PersonID
union select 3 as PurchaseID, 'PersonA' as PersonID
union select 4 as PurchaseID, 'PersonB' as PersonID
union select 5 as PurchaseID, 'TeamB' as PersonID
)
, Teams as (
select 1 as TeamID, 'PersonA' as PersonID
union select 1 as TeamID, 'TeamA' as PersonID
union select 1 as TeamID, 'PersonC' as PersonID
union select 2 as TeamID, 'PersonB' as PersonID
union select 2 as TeamID, 'TeamB' as PersonID
)
select Purchases.PurchaseID
, EveryTeamMember.PersonID
from Purchases
join Teams
on Teams.PersonID = Purchases.PersonID
cross apply (
select PersonID
from Teams InnerTable
where InnerTable.TeamID = Teams.TeamID
) as EveryTeamMember
where Purchases.PurchaseID = 1
If you are looking ti get all Team persons when the PersonID starts with Team then i think you should do a CROSS APPLY over all PersonID who starts with Team and UNION (NOT UNION ALL) Single Person purchases:
DECLARE #Purchases TABLE (
PurchaseID INT,
PersonID Varchar(50)
)
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamA', 1);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamA', 2);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('PersonA', 3);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('PersonB', 4);
INSERT INTO #Purchases(PersonID,PurchaseID) VALUES ('TeamB', 5);
DECLARE #Teams TABLE (
TeamID INT,
PersonID Varchar(50)
)
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonA', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('TeamA', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonC', 1);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('PersonB', 2);
INSERT INTO #Teams(PersonID,TeamID) VALUES ('TeamB', 2);
SELECT T1.PurchaseID,TeamPersons.PersonID
FROM #Purchases T1
INNER JOIN #Teams T2
ON T2.PersonID = T1.PersonID AND T1.PersonID LIKE'Team%'
CROSS APPLY (
SELECT PersonID
FROM #Teams T3
WHERE T3.TeamID = T2.TeamID
) AS TeamPersons
UNION
SELECT T1.PurchaseID
, T1.PersonID
FROM #Purchases T1
WHERE T1.PersonID NOT LIKE 'Team%'
Result

Displaying whole table after stripping characters in SQL Server

This question has 2 parts.
Part 1
I have a table "Groups":
group_ID person
-----------------------
1 Person 10
2 Person 11
3 Jack
4 Person 12
Note that not all data in the "person" column have the same format.
In SQL Server, I have used the following query to strip the "Person " characters out of the person column:
SELECT
REPLACE([person],'Person ','')
AS [person]
FROM Groups
I did not use UPDATE in the query above as I do not want to alter the data in the table.
The query returned this result:
person
------
10
11
12
However, I would like this result instead:
group_ID person
-------------------
1 10
2 11
3 Jack
4 12
What should be my query to achieve this result?
Part 2
I have another table "Details":
detail_ID group1 group2
-------------------------------
100 1 2
101 3 4
From the intended result in Part 1, where the numbers in the "person" column correspond to those in "group1" and "group2" of table "Details", how do I selectively convert the numbers in "person" to integers and join them with "Details"?
Note that all data under "person" in Part 1 are strings (nvarchar(100)).
Here is the intended query output:
detail_ID group1 group2
-------------------------------
100 10 11
101 Jack 12
Note that I do not wish to permanently alter anything in both tables and the intended output above is just a result of a SELECT query.
I don't think first part will be a problem here. Your query is working fine with your expected result.
Schema:
CREATE TABLE #Groups (group_ID INT, person VARCHAR(50));
INSERT INTO #Groups
SELECT 1,'Person 10'
UNION ALL
SELECT 2,'Person 11'
UNION ALL
SELECT 3,'Jack'
UNION ALL
SELECT 4,'Person 12';
CREATE TABLE #Details(detail_ID INT,group1 INT, group2 INT);
INSERT INTO #Details
SELECT 100, 1, 2
UNION ALL
SELECT 101, 3, 4 ;
Part 1:
For me your query is giving exactly what you are expecting
SELECT group_ID,REPLACE([person],'Person ','') AS person
FROM #Groups
+----------+--------+
| group_ID | person |
+----------+--------+
| 1 | 10 |
| 2 | 11 |
| 3 | Jack |
| 4 | 12 |
+----------+--------+
Part 2:
;WITH CTE AS(
SELECT group_ID
,REPLACE([person],'Person ','') AS person
FROM #Groups
)
SELECT D.detail_ID, G1.person, G2.person
FROM #Details D
INNER JOIN CTE G1 ON D.group1 = G1.group_ID
INNER JOIN CTE G2 ON D.group1 = G2.group_ID
Result:
+-----------+--------+--------+
| detail_ID | person | person |
+-----------+--------+--------+
| 100 | 10 | 10 |
| 101 | Jack | Jack |
+-----------+--------+--------+
Try following query, it should give you the desired output.
;WITH MT AS
(
SELECT
GroupId, REPLACE([person],'Person ','') Person
AS [person]
FROM Groups
)
SELECT Detail_Id , MT1.Person AS group1 , MT2.Person AS AS group2
FROM
Details D
INNER JOIN MT MT1 ON MT1.GroupId = D.group1
INNER JOIN MT MT2 ON MT2.GroupId= D.group2
The first query works
declare #T table (id int primary key, name varchar(10));
insert into #T values
(1, 'Person 10')
, (2, 'Person 11')
, (3, 'Jack')
, (4, 'Person 12');
declare #G table (id int primary key, grp1 int, grp2 int);
insert into #G values
(100, 1, 2)
, (101, 3, 4);
with cte as
( select t.id, t.name, ltrim(rtrim(replace(t.name, 'person', ''))) as sp
from #T t
)
-- select * from cte order by cte.id;
select g.id, c1.sp as grp1, c2.sp as grp2
from #G g
join cte c1
on c1.id = g.grp1
join cte c2
on c2.id = g.grp2
order
by g.id;
id grp1 grp2
----------- ----------- -----------
100 10 11
101 Jack 12

Count Values associated with key in Sql Server

I have three tables
Table Category
CategoryID Category
1 Climate
2 Area
Table CategoryDetail
DetailID CategoryID Desc
1 1 Hot
2 1 Cold
3 2 Area1
Table CategoryDetailValues
PK AnotherFK CategoryDetailID
1 1 1
2 1 1
3 1 2
4 2 1
Here AnotherFK is foreign key referring to another table. In record 1 and 2 duplicate exists that's ok but AnotherFK 1 has reference of CategoryDetailID 1 and 2 which has categoryID of 1 which is not ok
So from above tables
this result is valid from above three table
PK AnotherFK CategoryID DetailID Desc
1 1 1 1 Hot
2 1 1 1 Hot
But below result is not valid
PK AnotherFK CategoryID DetailID Desc
2 1 1 1 Hot
3 1 1 2 Cold
I can not put same AnotherFK in two different DetailID which has same CategoryID. I could have eliminated this by introducing CategoryID in CategoryDetailValues table and creating unique constraint but I am not allowed to do so.
Now my aim is to find all those record in CategoryDetailValues table which has different DetailID that are associated with same CategoryID. So that I can delete them.
Trying to achieve this in SQL Server 2012.
If your goal is to highlight all AnotherFK cases that have the same CategoryID, but differenty DetailIDs, the following ought to do the trick (pseudo-code):
SELECT * FROM (SELECT AnotherFK, ROW_NUMBER() OVER
(ORDER BY AnotherFK, CategoryID) AS rn FROM #myTable) AS a
WHERE rn > 1
Sample code:
CREATE TABLE #myTable
(
AnotherFK int
, CategoryID int
, DetailID int
) ;
INSERT INTO #myTable (
AnotherFK
, CategoryID
, DetailID
)
VALUES (1, 1, 1)
, (1, 1, 2);
SELECT * FROM (SELECT AnotherFK, ROW_NUMBER() OVER (ORDER BY AnotherFK, CategoryID) AS rn FROM #myTable) AS a
WHERE rn > 1
DROP TABLE #myTable
If this is not what you are after, please elaborate
I think you could use something like this:
Script to create sample tables:
CREATE TABLE mytable(
PK INTEGER NOT NULL PRIMARY KEY
,AnotherFK INTEGER NOT NULL
,CategoryDetailID INTEGER NOT NULL
);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (1,1,1);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (2,1,1);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (3,1,2);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (4,2,1);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (5,1,3);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (6,1,3);
INSERT INTO mytable(PK,AnotherFK,CategoryDetailID) VALUES (7,1,3);
CREATE TABLE mytable2(
DetailID INTEGER NOT NULL
,CategoryID INTEGER NOT NULL
,Descr VARCHAR(5) NOT NULL
);
Query to show "suspect" record (I think you have to decide what records delete...):
SELECT * FROM (
SELECT * ,COUNT(*) OVER (PARTITION BY CategoryID, ANotherFK) AS X
, COUNT(*) OVER (PARTITION BY CategoryID, DetailID, ANotherFK) AS X1
FROM mytable A
INNER JOIN mytable2 B ON A.CategoryDetailID= B.DetailID
)C
WHERE X-X1 >0
Output:
+--+----+-----------+------------------+----------+------------+-------+---+----+
| | PK | AnotherFK | CategoryDetailID | DetailID | CategoryID | Descr | X | X1 |
+--+----+-----------+------------------+----------+------------+-------+---+----+
| | 1 | 1 | 1 | 1 | 1 | Hot | 3 | 2 |
| | 2 | 1 | 1 | 1 | 1 | Hot | 3 | 2 |
| | 3 | 1 | 2 | 2 | 1 | Cold | 3 | 1 |
+--+----+-----------+------------------+----------+------------+-------+---+----+
This query will look in Categorydetail for records with duplicate DetailID. Than join the tables to provide you the details. It's still up to you to decide which records should be deleted.
select *
from(
Select CategoryID
from CategoryDetail
group by CategoryID
having count(DetailID)>1)aggr
join CategoryDetail c on aggr.CategoryID = c.CategoryID
join CategoryDetailValues v on c.CategoryDetailID = v.CategoryDetailID
You want one value per AnotherFK and Category. So the third table should have a composite key:
CategoryDetailValues(AnotherFK, CategoryID, DetailID, HowMany)
with a unique constraint on AnotherFK, CategoryID and both building a foreign key to CategoryDetail(CategoryID, DetailID).
In order to clean up data first, you'd have to look for ambiguities:
select AnotherFK, CategoryID, DetailID
from
(
select
cdv.AnotherFK, cd.CategoryID, cdv.DetailID,
count(distinct cd.DetailID) over (partition by cdv.AnotherFK, cd.CategoryID) as cnt
from CategoryDetailValues cdv
join CategoryDetail cd on cd.DetailID = cdv.CategoryDetailID
)
where cnt > 1
order by AnotherFK, CategoryID, DetailID
You could try this solution that comes with following assumption: within CDV table, for every [AnotherFK] value (ex. 1) should be displayed only those rows with the minimum [CategoryDetailID] (ex. 1)
SELECT *
FROM (
SELECT cdv.PK, cdv.AnotherFK, cd.CategoryID, cd.[Desc],
Rnk = DENSE_RANK() OVER(PARTITION BY cdv.AnotherFK ORDER BY cdv.CategoryDetailID)
FROM dbo.CategoryDetailValues cdv
JOIN dbo.CategoryDetail cd ON cd.DetailID = cdv.DetailID
WHERE cdv.AnotherFK = 1
) x
WHERE x.Rnk = 1

Oracle: Left join very big table and limit the joined rows to one with the largest field value

I have two tables. The second one references to the first one by m_id.
Main table
M_ID | M_FIELD
1 | 'main1'
2 | 'main2'
3 | 'main3'
Sub-table
S_ID | S_FIELD | S_ORDER | M_ID
1 | 'sub1-1' | 1 | 1
2 | 'sub1-2' | 2 | 1
3 | 'sub1-3' | 3 | 1
4 | 'sub2-1' | 1 | 2
5 | 'sub2-2' | 2 | 2
6 | 'sub2-3' | 3 | 2
7 | 'sub3-1' | 1 | 3
8 | 'sub3-2' | 2 | 3
9 | 'sub3-3' | 3 | 3
I need to join these two tables (by M_ID) but from the Sub-table I need only the row with the largest value of S_ORDER.
So the expected result of the query is:
M_ID | M_FIELD | S_FIELD
1 | 'main1' | 'sub1-3'
2 | 'main2' | 'sub2-3'
3 | 'main3' | 'sub3-3'
There is working solution with analytical function in the answer of this question: How do I limit the number of rows returned by this LEFT JOIN to one?
(I will post it at the bottom)
But the problem is that Sub-Table is very big (and is actually a view with some inner calculations) and this kind of subquery works way too long. So I suppose I need to filter out the table by m_id first and only after that find the field with the largest S_ORDER
I need something simple like this (which fails because the second level subquery doesn't see the M.M_ID field outside):
SELECT m.*,
(SELECT s_field
FROM (SELECT s_field
FROM t_sub s
WHERE s.m_id = m.m_id
ORDER BY s_order DESC)
WHERE ROWNUM = 1) s_field
FROM t_main m;
The code to create and populate the test schema:
CREATE TABLE t_main (m_id NUMBER PRIMARY KEY,
m_field VARCHAR2(10));
CREATE TABLE t_sub (s_id NUMBER PRIMARY KEY,
s_field VARCHAR2(10),
s_order NUMBER,
m_id NUMBER );
INSERT INTO t_main VALUES (1,'main1');
INSERT INTO t_main VALUES (2,'main2');
INSERT INTO t_main VALUES (3,'main3');
INSERT INTO t_sub VALUES (1,'sub1-1', 1, 1);
INSERT INTO t_sub VALUES (2,'sub1-2', 2, 1);
INSERT INTO t_sub VALUES (3,'sub1-3', 3, 1);
INSERT INTO t_sub VALUES (4,'sub2-1', 1, 2);
INSERT INTO t_sub VALUES (5,'sub2-2', 2, 2);
INSERT INTO t_sub VALUES (6,'sub2-3', 3, 2);
INSERT INTO t_sub VALUES (7,'sub3-1', 1, 3);
INSERT INTO t_sub VALUES (8,'sub3-2', 2, 3);
INSERT INTO t_sub VALUES (9,'sub3-3', 3, 3);
COMMIT;
Working solution mentioned above (working too slow with large T_SUB table):
SELECT m.*,
s.s_field
FROM t_main m
LEFT JOIN
(SELECT *
FROM
(SELECT ts.*,
ROW_NUMBER() OVER (PARTITION BY m_id
ORDER BY s_order DESC) AS seq
FROM t_sub ts)
WHERE seq = 1) s ON s.m_id = m.m_id;
The DB we use is Oracle 10g
Thank you very much for your help
try this
SELECT m.*,
(select s.s_field
from t_sub s
where s.m_id = m.m_id
and s.s_order = (select max(s_order) from t_sub where t_sub.m_id = s.m_id)
and rownum = 1)
FROM t_main m
or you can try this (it's your code but some modifications)
SELECT m.*,
(select s.s_field from
(SELECT s_field, m_id
FROM t_sub
--where t_sub.m_id = m.m_id
order by s_order DESC) s
where s.m_id = m.m_id
and rownum = 1)
FROM t_main m
select t.*, s.s_field from t_main t
left join (select m_id, min(s_field) keep(dense_rank first order by s_order desc) as s_field
from t_sub group by m_id) s on (s.m_id = t.m_id)