Get one record per ID - sql

I'm trying to retrieve data from 2 tables A&B.
(select * from tableA a LEFT JOIN tableB b on a.idA = b.idA)
, there are multiple data rows in B for each PrimaryKey from A. But I want to get only the first record for every ID from tableA. How can I achieve this?

SQL tables represent unordered sets so there is no first row. But you can get an arbitrary row or specific row based on an ordering column using window functions:
select *
from tableA a LEFT JOIN
(select b.*,
row_number() over (partition by idA order by <ordering col>) as seqnum
from tableB b
) b
on a.idA = b.idA and seqnum = 1

Related

How to join large subset of data with smaller subset data

I have three tables in SQL Server
TABLE_A - contains 500 rows
TABLE_B - contains 1 million rows
TABLE_C - contains 1 million rows
I want to select the rows from TABLE_B and TABLE_C join with TABLE_A based on a row number position from TABLE_B and TABLE_C tables.
Below is my sample query:
SELECT TOP (50), *
INTO ##tempResult
FROM TABLE_A
LEFT JOIN
(SELECT *
FROM
(SELECT
memberID,
ROW_NUMBER() OVER (PARTITION BY TABLE_A.member_id ORDER BY TABLE_A EM.UTupdateDate DESC) AS rowNum,
FROM
TABLE_B
JOIN
TABLE_C ON TABLE_B.memberID = TABLE_C.memberID
)
) AS TABLE_subset
WHERE
TABLE_subset.rowNum <=2
) AS TABLE_INC ON TABLE_A.memberID = TABLE_INC.memberID
WHERE TABLE_A.colA = 'XYZ'
Here the TABLE_subset is joining entire records in TABLE_B and TABLE_C, but I want to join only the top 50 records with TABLE_A.
Is there any way to achieve this ?
Your question and query doesn't match exactly, but CROSS APPLY is probably your friend here.
The general idea is:
select TOP 50 *
from tableA a
CROSS APPLY (
SELECT TOP 2 b.id, c.otherid
from tableB b
inner join tableC c
ON c.id = b.id
where b.id = a.id -- Here you match field between A and B
order by b.date DESC -- order by something
) data
Now just need to adapt to your needs

How do I join two tables together (one to many relationship), but only select the 3rd match from the second table?

I have two tables, table A and table B. There are multiple entries in table B for each entry in table A when joining them together, but I only want to match the 3rd value from table B, which is neither the maximum nor the minimum of the values. The values can be ordered, and it will always be the 3rd value after ordering. Is there a way to do this? Thank you!
WITH
ranked_b AS
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY key ORDER BY val) AS key_rank
FROM
table_b
)
SELECT
*
FROM
table_a
INNER JOIN
ranked_b
ON ranked_b.key = table_a.key
AND ranked_b.key_rank = 3
Consider below approach
select key,
array_agg(value order by value limit 3)[safe_ordinal(3)] as value
from tableA
left join tableB
on key = foreignkey
group by key
You can use a correlated subquery:
select a.*,
(select b.value
from b
where b.key = a.key
limit 1 offset 2
)
from a;

Return 1 result with left join from table B

Table A Table B Table B Table B
Itemnr Itemnr Item Status Remark
100000 100000 1 Approved
200000 100000 2 Use up
100000 3 Obsolete
200000 1 Approved
200000 2 Use up
200000 3 Obsolete
I would like to see only one result per line in table A item with as result the Remark based on Item status 1. I tried a lot with the option of a left join but without the good result.
Is this what you want?
select a.itemnr, b.remark
from tablea a
inner join tableb b on b.itemnr = a.itemnr and b.item_status = 1
If some records in tablea might not have a corresponding row in tableb with item_status = 1 and you want to keep these in the resultset, then you can use left join instead of inner join.
For the data example you have provided, you don't need tablea:
select b.itemnr, b.remark
from tableb b
where b.item_status = 1;
You specify that you want a left join, which implies rows in tablea that are not in tableb, although you have no such examples in the question. In that case:
select a.itemnr, b.remark
from tablea a left join
tableb b
on b.itemnr = a.itemnr and b.item_status = 1;
You can use row_number()
select t.*
from (select a.*, b.*, row_number() over (partition by a.itemr order by b.status) as seq
from a inner join
b
on a.itemr = b.itemr
) t
where seq = 1;
This will return rows total itemrs along with first status. Also this assumes Itemnr, Item Status, Remark are the columns name.
EDIT : If you want to check, first status 1 is available or not then you can do :
SELECT a.itemr, b.remark
FROM a LEFT JOIN
b
ON b.itemr = a.itemr AND b.status = 1;

How to replace TOP 1000 rows of select columns indiscriminately

Basically I have a table that contains 1000 rows with three columns. (TABLE A)
I have ANOTHER table with 200 columns with 1million+ records. (TABLE B)
I am trying to replace the THREE COLUMNS OF 1000 rows of TABLE B with those of TABLE A. I've read a lot of solutions where you can INSERT into table B from TABLE A.. but that's useless because I'll get NULLs in the remaining 197 columns that I need data for.
So the task is to replace rows of certain columns from one table to select columns of another table. There is NO conditions, just the top rows or whatever order you can think of is fine. If you can give an answer that takes ORDER BY something into account, that'd be bonus! Thank you so much!
If I understood your requirements
WITH TA
AS (SELECT *,
ROW_NUMBER()
OVER (
ORDER BY col1) AS RN
FROM TableA),
TB
AS (SELECT *,
ROW_NUMBER()
OVER (
ORDER BY col1) AS RN
FROM TableB)
UPDATE TB
SET TB.col1 = TA.col1,
TB.col2 = TA.col2,
TB.col3 = TA.col3
FROM TB
JOIN TA
ON TB.RN = TA.RN
Try something like this:
WITH topB AS (
SELECT TOP 1000 row_number() OVER(ORDER BY field_n) rn, b.* FROM table_b b
ORDER BY field_x),
topA AS (
SELECT row_number() OVER(ORDER BY field_m) rn, a.*
FROM table_a a)
UPDATE b
SET
b.Field_1 = a.Field_1,
b.Field_2 = a.Field_2,
b.Field_3 = a.Field_3
FROM
TopB b JOIN TopA a ON b.rn = a.rn
Idea here is to assign row numbers in both tables, join them by these numbers, and update the B part of the join with values from A.

joining 2 tables with non unique IDs for merge

I need to migrate data from another table to mine. However, the ID i have to use to join them is not unique (~10% of the IDs from either tables are duplicated, they are not primary keys).
eg. table A has IDs (1, 1, 2, 3) and table B has values (1, 2, 2, 3, 4) how can I join them so they either omit duplicates or take ANY value from the other table as the correct link?
My goal is to return a view where there are no duplicate rows at all in the ID column I am joining on.
How about using row_number() for the query:
select a.*, b.*
from (select a.*, row_number() over (partition by id order by id) as seqnum
from tablea a
) a join
(select b.*, row_number() over (partition by id order by id) as seqnum
from tableb b
) b
on a.id = b.id and a.seqnum = 1 and b.seqnum = 1;