Inner join of table a and table b with selecting only one row of multiple in table b ( row with colum n = max value ) - sql

i am a total beginner in SQL. So i have two tables ( table a and table b )
table a holds people with unique IDs, table b holds multiple rows for each person of table a and also the persons ID ( for a possible join ) . the rows in table b are sorted by the columnn row_number.
How can i select all people but only the row of table b with the highest row_number ?
i hope you could somewhat understand me.
Cheers

If i got you right:
SELECT a.persons_ID
,b.rn
FROM A
INNER JOIN
(
SELECT MAX(row_number_column) AS rn
,persons_ID
FROM B
GROUP BY persons_ID
) sub
ON sub.persons_ID = A.persons_ID
The subselect in the inner joins groups your data of table B. So there will be just one row for each persons_ID - the row with the highest row_number_column.
Finally just a simple join on persons_ID.

If you don't need any other information than the person ID and the last row_number per person, then it is quite trivial. Let's call the first table person and the second visit:
select person_id,
max(row_number) max_row_number
from visit
group by person_id
If you need some other information from the first table, like person.name, then perform the join:
select person.person_id,
person.name,
max(visit.row_number) max_row_number
from person
inner join visit on visit.person_id = person.person_id
group by person.person_id,
person.name
If you need some other information from the second table, like visit.present, then modern databases support the row_number() window function (not to be confused with the column that you have):
select name,
base.row_number,
present
from (
select person.name,
row_number() over (partition by visit.person_id
order by visit.row_number desc) rn,
visit.row_number,
visit.present
from person
inner join visit on visit.person_id = person.person_id
) base
where rn = 1
NB: I would strongly advise to rename the column row_number to some other name, as row_number is an analytic function in many databases.

Related

Subtracting values of columns from two different tables

I would like to take values from one table column and subtract those values from another column from another table.
I was able to achieve this by joining those tables and then subtracting both columns from each other.
Data from first table:
SELECT max_participants FROM courses ORDER BY id;
Data from second table:
SELECT COUNT(id) FROM participations GROUP BY course_id ORDER BY course_id;
Here is some code:
SELECT max_participants - participations AS free_places FROM
(
SELECT max_participants, COUNT(participations.id) AS participations
FROM courses
INNER JOIN participations ON participations.course_id = courses.id
GROUP BY courses.max_participants, participations.course_id
ORDER BY participations.course_id
) AS course_places;
In general, it works, but I was wondering, if there is some way to make it simplier or maybe my approach isn't correct and this code will not work in some conditions? Maybe it needs to be optimized.
I've read some information about not to rely on natural order of result set in databases and that information made my doubts to appear.
If you want the values per course, I would recommend:
SELECT c.id, (c.max_participants - COUNT(p.id)) AS free_places
FROM courses c LEFT JOIN
participations p
ON p.course_id = c.id
GROUP BY c.id, c.max_participants
ORDER BY 1;
Note the LEFT JOIN to be sure all courses are included, even those with no participants.
The overall number is a little tricker. One method is to use the above as a subquery. Alternatively, you can pre-aggregate each table:
select c.max_participants - p.num_participants
from (select sum(max_participants) as max_participants from courses) c cross join
(select count(*) as num_participants from participants from participations) p;

Get Limited Records For Sub Query Each Result

I am trying to query some data from SQL Server 2012 using sub query. I am trying to get first 3 records for each Id returned by Sub Query but I am not getting the idea how to do so for now I write this query:
Select * from Student Where TeacherId in (Select TeacherId from Teacher)
I am not sure if this is achievable by using such query or do I have to write a function or any thing else ?
Any Suggestions would be great and sorry for my bad explanation skills.
You should join the Teacher to Student table, and then use an analytic function to get the first there records for each teacher:
SELECT *
FROM
(
SELECT
s.*, t.TeacherId, t.TeacherName,
ROW_NUMBER() OVER (PARTITION BY t.TeacherId ORDER BY some_col) rn
FROM Teacher t
INNER JOIN Student s
ON t.TeacherId = s.TeacherId
) t
WHERE rn = 3;
I assume that there is a column in one of the two tables some_col which you want to use for ordering. It does not make much sense to speak of the first three records without also defining some ordering.
I guess you want the top 3 rows for each ids, not top 3 rows for entire result set
WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY t.TeacherId ORDER BY ?) Seq
FROM Student s
INNER JOIN Teacher t ON t.TeacherId = s.TeacherId
)
SELECT * FROM CTE
WHERE Seq between 1 AND 3
? placeholder requires column_name to generate the sequence_number to get the result with boundary of 1 to 3 .

How to group my table for latest date and ID?

I have a table like this:
I need group this table latest date for every ID.
I mean, I want to get last row every ID. Here is my query:
SELECT DISTINCT ch.Date,ID FROM dbo.tblrisk AS rk
inner join (Select TableIdentity, [Date] from tblCommonHistory ) ch
ON ch.TableIDentity = rk.ID order by ID
How can I do what I want?
EDIT: This query worked for me:
SELECT DISTINCT ch.dt,ID FROM dbo.tblrisk AS rk
inner join (Select TableIdentity, max([Date]) as dt from tblCommonHistory group by TableIdentity) ch ON ch.TableIDentity = rk.ID order by ID
Just use aggregation:
select TableIdentity, max([date])
from tblCommonHistory
group by TableIdentity;
Your question only mentions one table. Your query has two; I don't understand the discrepancy.
It's strange that you have duplicated TableIdentity in tblCommonHistory, but otherwise you should not be getting multiple dates for the same ID from your query.
And also, the only reason to join the 2 tables seems to be that you need to skip those ID that are not present in the tblrisk (is it what you need to do?)
In that case, I'd suggest
SELECT max(ch.Date) AS [Date],ID FROM dbo.tblrisk AS rk
inner join tblCommonHistory AS ch ON ch.TableIDentity = rk.ID
group by ID order by ID

SQL Inner Join using Distinct and Order by Desc

table a.
Table b . I have two tables. Table A has over 8000+ records and continues to grow with time.
Table B has only 5 or so records and grows rarely but does grow sometimes.
I want to query Table A's last records where the Id for Table A matches for Table B. The problem is; I am getting all the rows from Table A. I just need the ones where Table A and B match once. These are unique Id's when a new row is inserted into table B and never get repeated.
Any help is most appreciated.
SELECT a.nshift,
a.loeeworkcellid,
b.loeeconfigworkcellid,
b.loeescheduleid,
b.sdescription,
b.sshortname
FROM oeeworkcell a
INNER JOIN dbo.oeeconfigworkcell b
ON a.loeeconfigworkcellid = b.loeeconfigworkcellid
ORDER BY a.loeeworkcellid DESC
I am assuming you want to get the only the lastest (as you said) row from the TableA but JOIN giving you all the rows.You can use the Row_Number() to get the rownumber and then apply the join and filter it with the Where clause to select only the first row from the JOIN. So what you can try as below,
;WITH CTE
AS
(
SELECT * , ROW_NUMBER() OVER(PARTITION BY loeeconfigworkcellid ORDER BY loeeworkcellid desc) AS Rn
FROM oeeworkcell
)
SELECT a.nshift,
a.loeeworkcellid,
b.loeecoonfigworkcellid,
b.loeescheduleid,
b.sdescription,
b.sshortname
FROM CTE a
INNER JOIN dbo.oeeconfigworkcell b
ON a.loeeconfigworkcellid = b.loeeconfigworkcellid
WHERE
a.Rn = 1
You need to group by your data and select only the data having the condition with min id.
SELECT a.nshift,
a.loeeworkcellid,
b.loeecoonfigworkcellid,
b.loeescheduleid,
b.sdescription,
b.sshortname
FROM oeeworkcell a
INNER JOIN dbo.oeeconfigworkcell b
ON a.loeeconfigworkcellid = b.loeeconfigworkcellid
group by
a.nshift,
a.loeeworkcellid,
b.loeecoonfigworkcellid,
b.loeescheduleid,
b.sdescription,
b.sshortname
having a.loeeworkcellid = min(a.loeeworkcellid)

Adding rows to SQL query for each element in WHERE sequence

I have an SQL query like the following:
SELECT store_id, SUM(quantity_sold) AS count
FROM sales_table
WHERE store_id IN ('Store1', 'Store2', 'Store3')
GROUP BY store_id;
This returns a row for each store that has rows in sales_table, but does not return a row for those that do not. What I want is one row per store, with a 0 for count if it has no records.
How can I do this, assuming that I do not have access to a stores table?
with stores (store_id) as (
values ('Store1'), ('Store2'), ('Store3')
)
select st.store_id,
sum(sal.quantity_sold) as cnt
from stores st
left join sales_table sal on sal.store_id = st.store_id
group by st.store_id;
If you do have a stores table, then simply do an outer join to that one instead of "making one up" using the common table expression (with ..).
This can also be written without the CTE (common table expression):
select st.store_id,
sum(sal.quantity_sold) as cnt
from (
values ('Store1'), ('Store2'), ('Store3')
) st
left join sales_table sal on sal.store_id = st.store_id
group by st.store_id;
(But I find the CTE version easier to understand)
You can use unnest() to generate rows from array elements.
SELECT store, sum(sales_table.quantity_sold) AS count
FROM unnest(ARRAY['Store1', 'Store2', 'Store3']) AS store
LEFT JOIN sales_table ON (sales_table.store_id = store)
GROUP BY store;