Sql join only 1 row - sql

I want to join the table CustomerAgreementRole with only one row from AgreementRoleGroup, based on ViewPriority. Example: CustomerAgreementRole can have three rows. I only want the joined row where ViewPriority is highest
AgreementId, AgreementRoleId
1 1
1 2
1 3
CustomerAgreementRole
1. AgreementId
2. AgreementRoleId
AgreementRoleGroup
1. AgreementRoleId
2. ViewPriority
Current query:
select * from CustomerAgreementRole car
join (select agreementRoleId, min(ViewPriority) as mi from AgreementRoleGroup group by AgreementRoleId) as arg on car.AgreementRoleId = arg.AgreementRoleId
Expected result:
AgreementId, AgreementRoleId, ViewPriority
1 1 1

May be something like this:
SELECT *
FROM CustomerAgreementRole A
CROSS APPLY
(
SELECT TOP 1 *
FROM AgreementRoleGroup B
WHERE A.[AgreementRoleId] = B.[AgreementRoleId]
ORDER BY ViewPriority DESC
) C

Since AgreementRoleGroup already got AgreementRoleId we can just join with some subquery
select a.*, b2.ViewPriority from CustomerAgreementRole a left join
(
select b.AgreementRoleId, b.ViewPriority
from AgreementRoleGroup b
where b.ViewPriority =
(
select min(ViewPriority)
from AgreementRoleGroup
)
) b2
on a.AgreementRoleId=b2.AgreementRoleId
But I'll say that using min() isn't the best way,you should use top in #gotqn answer but right now this will work.
re-edit
create table CustomerAgreementRole (AgreementId int,AgreementRoleId int);
insert into CustomerAgreementRole values (1,1);
insert into CustomerAgreementRole values (2,3);
insert into CustomerAgreementRole values (3,4);
insert into CustomerAgreementRole values (4,2);
create table AgreementRoleGroup (AgreementRoleId int, ViewPriority int);
insert into AgreementRoleGroup values (1,3);
insert into AgreementRoleGroup values (3,4);
insert into AgreementRoleGroup values (4,2);
insert into AgreementRoleGroup values (2,1);
I use those as sample data and got this result db<>fiddle
if you just want that one row and don't care ViewPriority need to be min, use top instead
select top 1 a.*, b.ViewPriority from CustomerAgreementRole a left join
AgreementRoleGroup b
on a.AgreementRoleId=b.AgreementRoleId
order by ViewPriority asc

Per AgreementId you want the AgreementRoleId with the highest priority (lowest ViewPriority value). This means you want to rank the CustomerAgreementRole rows and only show the best ranked ones. Ranking is typically done with ROW_NUMBER, RANK or DENSE_RANK in SQL.
select AgreementId, AgreementRoleId, ViewPriority
from
(
select
car.AgreementId, car.AgreementRoleId, arg.ViewPriority,
row_number() over (partition by car.AgreementId order by arg.ViewPriority) as rn
from CustomerAgreementRole car
join AgreementRoleGroup arg on arg.AgreementRoleId = car.AgreementRoleId
) ranked
where rn = 1;

Made it working with this:
WITH CTEViewPriority (lowestViewPriority, agreementId) as (
select min(ViewPriority), AgreementId from CustomerAgreementRole as car
left join AgreementRoleGroup arg on car.AgreementRoleId = arg.AgreementRoleId
group by agreementId
)
select * from CustomerAgreementRole as car
inner join CTEViewPriority as arg on lowestViewPriority = arg.agreementRoleId and arg.agreementId = car.agreementId

Related

MariaDB concatenate 2 tables with same number of rows

Say I have 2 tables with exactly SAME number of rows, but no other obvious relations:
tableA
ID
items
1
banana
2
orange
tableB
itemID
volume
5550
50
5551
70
Can I join these 2 tables horizontally, to form 1 table like the following?
ID
items
itemID
volume
1
banana
5550
50
2
orange
5551
70
If you have 2 tables with exactly SAME number of rows, but no other obvious relations and on both tables , respectively ID and itemID defines the uniqueness of the rows you can apply MySQL ROW_NUMBER Function and join on the row_number, the order by clause is important.
Try:
SELECT tbla.ID, tbla.Items, tblb.ItemId, tblb.volume
FROM (
SELECT ID, Items, row_number() over( order by ID desc )row_numA
FROM TableA
)tbla
INNER join
( SELECT ItemId,volume,row_number() over(order by ItemId desc)row_numB
FROM TableB
) tblb ON tbla.row_numA=tblb.row_numB
order by tbla.ID asc;
https://dbfiddle.uk/?rdbms=mariadb_10.6&fiddle=15d13d29a84a55c4d029115c87eebe8f
try this
create table TableA(ID INT, Items varchar(20));
create table TableB(ItemId INT, volume varchar(20));
insert into TableA(Id, items) values (1, 'banana'), (2, 'orange');
insert into TableB(ItemId, volume) values (5550, '50'), (5551, '70');
SELECT A.ID, A.Items, B.ItemId, B.volume
FROM
(
SELECT ID, Items, rownum()R
FROM TableA
)A INNER join
(
SELECT ItemId,volume,rownum()R
FROM TableB
)B ON A.R=B.R

Finding Occurrence of the duplicate values

I have table with 3 columns (id, Name, Occurrence), I want to update the Occurrence column ,based on the id column, attached snap for the reference.
for example if my id column has "606" value 3 times then my occurrent column should have 3 against all the "606" value.
Below is the method which I tried.
I tried to find the duplicate values using group by and Having clause and saved it in a temp table and from there I tried to join the table value from the temp table.
you can use window functions in an updatable CTE for this.
You haven't supplied any actual sample data so this is untested, however the following should work:
with x as (
select Id, Occurence, count(*) over(partition by Id) qty
from Table
)
update x
set Occurence = Qty;
You can go for GROUP BY based approach also.
declare #TABLE TABLE(ID INT, NAME CHAR(3), occurance int null)
insert into #TABLE VALUES
(1,'AAA',NULL),(1,'AAA',NULL),(2,'CCC',NULL),(3,'DDD',NULL), (3,'DDD',NULL),(4,'EEE',NULL),(5,'FFF',NULL);
;WITH CTE_Table as
(
SELECT ID, COUNT(*) AS Occurance
FROM #table
group by id
)
UPDATE t
SET occurance = c.occurance
FROM #table t
INNER JOIN CTE_Table as c
on C.ID = T.ID
SELECT * FROM #TABLE
ID
NAME
occurance
1
AAA
2
1
AAA
2
2
CCC
1
3
DDD
2
3
DDD
2
4
EEE
1
5
FFF
1
You can use a CTE and calculate row number and update your table base on CTE
;WITH q
AS
(
SELECT Id,COUNT(1) 'RowNum'
FROM YourTable
GROUP BY Id
)
UPDATE YourTable
SET Occurrence=q.RowNum
FROM YourTable t
INNER JOIN q
ON t.Id=q.Id

How can I print the first three rows and the last three rows one under another in ORACLE SQL?

In ORACLE SQL, I want to print the first two and the last two rows one under the other. How can I do this with a one query? Suppose you have table with ten rows. I want to print the first two rows and the last two rows as below:
Row Number
Values
1
A
2
B
9
C
10
D
You can use row_number()over(order by row_number) window function to achieve what you are looking for. Even you can have first two rows order by row_number and last two rows order by column valuess if you want (row_number()over(order by row_number)FirstRowNumber, row_number()over(order by valuess desc)LastRowNumber )).
Table structure and insert statement:
create table tableName (Row_Number int, Valuess varchar(20));
insert into tablename values(1,'A');
insert into tablename values(2,'B');
insert into tablename values(9,'C');
insert into tablename values(10,'D');
insert into tablename values(11,'E');
insert into tablename values(12,'F');
Query:
SELECT ROW_NUMBER,Valuess FROM (
select ROW_NUMBER,Valuess,row_number()over(order by row_number)FirstRowNumber, row_number()over(order by row_number desc)LastRowNumber from tablename ) T
WHERE FIRSTROWNUMBER<=2 OR LASTROWNUMBER<=2
ORDER BY FIRSTROWNUMBER
Output:
ROW_NUMBER
VALUESS
1
A
2
B
11
E
12
F
I think you need below query,
select t.*
from (select table1.*, row_number() over (order by [Row Number]) as seqnum,
count(*) over () as cnt
from table1
) t
where seqnum in( 1,2) or seqnum in( cnt, cnt-1);

How to Select one Value for each row after Joining of 2 Tables

I have 2 tables, the first one has 10 distinct values:
,
each GlobalPnID has many values on the second table, I want to join 2 tables and select one random value of PortionKey of the second table that match the condition and move to the next GlobalPnID
SELECT TOP 10 gpnp.PortionKey, tt.GlobalPnID
from #TempTable tt
LEFT JOIN [dbo].[GlobalPartNumberPortions] gpnp ON gpnp.GlobalPnId = tt.GlobalPnID
-- tt is the first table
-- gpnp is the second
SELECT TT.GlobalPnID,X.PortionKey
FROM #TempTable AS TT
CROSS APPLY
(
SELECT TOP 1 R.PortionKey
FROM [dbo].[GlobalPartNumberPortions] AS R
WHERE R.GlobalPnId=TT.GlobalPnID
ORDER BY R.PortionID
)X
You could use Row_Number with a CTE and set the criteria you want, for example:
DECLARE #TempTable TABLE
(
globalpnid INT
)
DECLARE #GlobalPartNumberPortions TABLE
(
portionid INT,
portionkey NVARCHAR(10),
globalpnid INT
)
INSERT INTO #TempTable
(globalpnid)
VALUES (1),(2),(3),(4)
INSERT INTO #GlobalPartNumberPortions
(portionid,
portionkey,
globalpnid)
VALUES (1,'ABC',1),
(2,'XYZ',1),
(3,'AZZ',2),
(4,'QWE',3),
(5,'TYU',4);
WITH cteportion
AS (SELECT portionkey,
globalpnid,
rn = Row_number()
OVER (
partition BY globalpnid
ORDER BY RAND(CHECKSUM(NEWID()))))
FROM #GlobalPartNumberPortions)
SELECT gpnp.portionkey,
tt.globalpnid
FROM #TempTable tt
LEFT JOIN cteportion gpnp
ON tt.globalpnid = gpnp.globalpnid
AND gpnp.rn = 1
This will partition the second table by the globalpnid ordering on ORDER BY RAND(CHECKSUM(NEWID()))) and you can then use this in the join gpnp.rn = 1. In the example I've included, you'll see that GlobalPnID = 1 will alternate between ABC and XYZ.
Edit: as suggested by #Thorsten Kettner in the comment, you can order by RAND(CHECKSUM(NEWID())))

how to insert many records excluding some

I want to create a table with a subset of records from a master table.
for example, i have:
id name code
1 peter 73
2 carl 84
3 jack 73
I want to store peter and carl but not jack because has same peter's code.
I need hight performance because i have 20M records.
I try this:
SELECT id, name, DISTINCT(code) INTO new_tab
FROM old_tab
WHERE (conditions)
but don't work.
Assuming you want to pick the row with the maximum id per code, then this should do it:
insert into new_tab (id, name, code)
(SELECT id, name, code
FROM
(
SELECT id, name, code, rank() as rnk OVER (PARTITION BY code ORDER BY id DESC)
FROM old_tab WHERE rnk = 1
)
)
and for the minimum id per code, just change the sort order in the rank from DESC to ASC:
insert into new_tab (id, name, code)
(SELECT id, name, code
FROM
(
SELECT id, name, code, rank() as rnk OVER (PARTITION BY code ORDER BY id ASC)
FROM old_tab WHERE rnk = 1
)
)
Using a derived table, you can find the minID for each code, then join back to that in the outer to get the rest of the columns for that ID from oldTab.
select id,name,code
insert into newTabFROM
from old_tab t inner join
(SELECT min(id) as minId, code
from old_tab group by code) x
on t.id = x.minId
WHERE (conditions)
Try this:
CREATE TABLE #Temp
(
ID INT,
Name VARCHAR(50),
Code INT
)
INSERT #Temp VALUES (1, 'Peter', 73)
INSERT #Temp VALUES (2, 'Carl', 84)
INSERT #Temp VALUES (3, 'Jack', 73)
SELECT t2.ID, t2.Name, t2.Code
FROM #Temp t2
JOIN (
SELECT t.Code, MIN(t.ID) ID
FROM #temp t
JOIN (
SELECT DISTINCT Code
FROM #Temp
) d
ON t.Code = d.Code
GROUP BY t.Code
) b
ON t2.ID = b.ID