Convert one-to-many relationship to one-to-one in SQL - sql

I have two tables, A and B
Table A:
Id int
Id_B int (FK with B)
Table B:
Id
Current state: An Id in table A can have multiple Id_B relationships, and two Id from table A can have the same Id_B
New state: I wish to make it so that two Id from table A cannot have the same Id_b. If I find such a relationship then create a new Id in table B and link it to the Id in table A to enforce the aforementioned constraint
I am lost on where to begin with this in SQL.
Before
Table A
Id
Id_B
1
1
1
4
2
1
3
2
4
3
Table B
Id
1
2
3
4
After (since there were two occurrences of 1 in the Id_B column, I created a new row in table B (with id 5), and assigned the Id of this to the Id 2 in table A to enforce uniqueness)
Table A
Id
Id_B
1
1
1
4
2
5
3
2
4
3
Table B
Id
1
2
3
4
5

Find all duplicate A.B_ID rows, add new B rows for the duplicates and update the corresponding A.B_ID.
Start with a query like:
with q as
(
select *, row_number() over (partition by B_ID, order by ID) rn
from A
)
select *
from q
where rn > 1
Add a unique constraint on A.B_ID

Related

Identify rows containing repeating customers and assigning them new id as per serial number generated in sql

I have a table
id
repeat customer id
store
date
1
A
07-19-22
2
A
07-19-22
3
A
07-19-22
id
repeat customer id
store
date
1
B
07-19-22
2
B
07-19-22
3
1
B
07-19-22
4
B
07-19-22
and more tables from other store
The problem here is
all stores start with id 1
repeat customer have new id in id column and their original id is retained in repeat customer id column
I have to concatenated all the tables and also keep track of repeating customer for analytics. I have joined all tables using UNION ALL and also created a dummy id column using SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NEW_ID, * FROM CTE, but I have no clue how to capture and assign value to repeat customer id such that I get the table as below
NEW_ID
id
new_repeat_customer_id
repeat customer id
store
date
1
1
A
07-19-22
2
2
A
07-19-22
3
3
A
07-19-22
4
1
B
07-19-22
5
2
B
07-19-22
6
3
4
1
B
07-19-22
7
4
B
07-19-22
The best way to incorporate it, would be to use Alphanumeric String as NEW_ID, and concat STORE and ID to create NEW_ID. For example A_000000001. In that way you can add similar STORE to REPEAT_CUSTOMER_ID as well.
So in this case, instead of NEW_ID=6, you would have NEW_ID=B_000000003 and REPEAT_CUSTOMER_ID would become B_000000001.
But in case that is not possible, you can use query like below to get the output
DB Fiddle Query
with CTE as
(
select * from STORE1
UNION ALL
select * from STORE2
)
,CTE2 as
(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT 1)) AS NEW_ID,t.* from CTE t)
,REPEAT_ID as
(select NEW_ID,ID,REPEAT_CUSTOMER_ID,STORE from CTE2 where REPEAT_CUSTOMER_ID is not null)
,REPEACT_CUSTOMER_ID as
(select c.NEW_ID as NEW_REPEAT_CUSTOMER_ID,r.NEW_ID
from REPEAT_ID r
left join CTE2 c
on c.ID=r.REPEAT_CUSTOMER_ID and c.STORE=r.STORE
)
select c.* , n.NEW_REPEAT_CUSTOMER_ID
from CTE2 c
left join REPEACT_CUSTOMER_ID n
on c.NEW_ID=n.NEW_ID
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=cbe63994b10f9e3b0eff53b0c89d463a
SO basically you have to separate rows where REPEATE customer is present and join it with main table query.

Get All elements from Table A that do not have a foreign key entry in table b [duplicate]

This question already has answers here:
Need SQL Query to find Parent records without child records
(6 answers)
Closed 3 years ago.
So I have 2 tables. Table B has a foreign key relationship with Table A.
For example.
Table A
id column 1 column 2
1 some thing
2 foo bar
3 hello world
4 this that
5 x y
Table B
id Table A id testcolumn
1 5 blah
2 5 blah
3 2 aggg
4 2 aggg
5 4 a
6 4 b
7 4 c
What I want is to select all of the elements from table A where there is no foreign key match in table B. In the case of the example I would want to select the row with id of 1 and 3 from table A. How would I accomplish that in a MS SQL database?
You can use an anti join:
select a.*
from a
left join b on a.id = b.table_a_id
where b.table_a_id is null

Update table column that is used for ordering according to alphabetical order on a second table

So I have two tables (A and B) that have a relation of n-n.
So there is a third table (C) that is used to connect both tables.
Table A and B both have an Id and a name.
Table C has IDA, IDB and an Order, the number that is used to sort and that is user given.
My issue is that I need to migrate table C since I just added that order column and so I need to give every line an ordering number, according to the B name.
So if table A has:
Id Name
1 A
2 B
3 C
And Table B has:
Id Name
1 J
2 L
3 M
And table C has:
IdA IdB Order
1 2 0
1 1 0
1 3 0
2 1 0
2 3 0
I need a query that updates table C to be more like:
IdA IdB Order
1 2 2
1 1 1
1 3 3
2 1 1
2 3 2
I have a query that can basically do what i want but it leaves me with "gaps"
reading my results above i get:
IdA IdB Order
1 2 2
1 1 1
1 3 3
2 1 1
2 3 3
I think this should work for what you need:
With ToUpdate As
(
Select C.*,
Row_Number() Over (Partition By C.IdA Order By B.Name) As NewOrder
From C
Join B On B.Id = C.IdB
)
Update C
Set "Order" = U.NewOrder
From ToUpdate U
Where U.IdA = C.IdA
And U.IdB = C.IdB
(In full disclosure, I'm not terribly familiar with postgres, but I think this should be valid).

Keep ID list after insert rows

I have table A like below
Table A:
ID Value
1 A
2 B
Note ID is auto Identity
Now I want to duplicate table A and keep new ID of new record inserted
My expectation after insert I have 2 table like below
Table A
ID Value
1 A
2 B
3 A
4 B
AND
Table IDList
Old_ID New_ID
1 3
2 4
NOTE Table IDList is temperary table to keep old and new ID
Perhaps simply:
SELECT Old_ID=MIN(ID), New_ID=MAX(ID)
FROM dbo.TableA
GROUP BY Value
demo

Most efficient way to get lists?

What's the best way to get a sublist of things?
I have two tables:
create table A (
id int primary key
)
create table B (
id int primary key,
aid int foreign key references A( id ),
sort_key int
)
I want to get a list of objects A, with subobjects B, but only the top five of B.
Let's say A is people, and B is type of food, with sort_key being how much a person likes that food. How do I get everybody (or some people) and their top 5 food?
On the previous comment if it's an INT you can't put non numerics in there.
Assuming the following data:
a
--
id
1
2
3
b
------------------------
id aid sort_key
1 1 1
2 1 2
3 2 1
4 3 1
5 1 3
6 1 4
7 1 5
8 1 6
9 2 2
10 2 3
The following query in MySQL would give you this:
SELECT a.*,
(SELECT GROUP_CONCAT(id) AS ids FROM b AS bi WHERE bi.aid = a.id ORDER BY sort_key LIMIT 5) AS ids
FROM a
Result:
id ids
1 1,2,5,6,7,8
2 3,9,10
3 4
This query assumes the sort key is one based, rather than zero:
SELECT a.name
b.food
FROM A a
JOIN B b ON b.aid = a.id
WHERE b.sortkey <= 5
ORDER BY a.name, b.sortkey