简体   繁体   English

SQL-左连接多对多仅一次

[英]SQL - Left Join many-to-many only once

I have a two tables that are setup like the following examples 我有两个像以下示例一样设置的表

tablea 桌子

ID | Name
1  | val1
1  | val2
1  | val3
2  | other1
3  | other

tableb 桌子

ID | Amount
1  | $100
2  | $50

My desired output would be to left join tableb to tablea but only join tableb once on each value. 我期望的输出是将连接tableb保留到tablea,但每个值仅连接一次tableb。 ID is the only relationship ID是唯一的关系

tablea.ID | tablea.Name | tableb.id | tableb.amount
1         | val1        | 1         | $100
1         | val2
1         | val3
2         | other1      | 2         | $50
3         | other     

Microsoft SQL Microsoft SQL

You can do the following: 您可以执行以下操作:

select ROW_NUMBER() OVER(ORDER BY RowID ASC) as RowNum, ID , Name
from tablea

which gives you : 这给你:

RowNum | RowID | Name
1      | 1     | val1
2      |1      | val2
3      |1      | val3
4      |2      | other1
5      |3      | other

You then get the minimum row number for each RowID: 然后,您将获得每个RowID的最小行号:

Select RowId, min(RowNum)
From (
    select ROW_NUMBER() OVER(ORDER BY RowID ASC) as RowNum, ID , Name
    from tablea )
Group By RowId

Once you have this you can then join tableb onto tablea only where the RowId is the minimum 一旦有了这个,就可以将tableb仅在RowId最小的情况下加入tablea

WITH cteTableA As (
    select ROW_NUMBER() OVER(ORDER BY RowID ASC) as RowNum, ID , Name
    from tablea ), 

cteTableAMin As (
    Select RowId, min(RowNum) as RowNumMin
    From cteTableA
    Group By RowId
    )
Select a.RowID, a.Name, b.Amount
From cteTableA a
Left join cteTableAMin amin on a.RowNum = amin.RowNumMin
                            and a.ID = amin.RowId
Left join tableb b on amin.ID = b.ID

This can be tidied up... but helps to show whats going on. 可以整理一下...但是有助于显示发生了什么。

Then you MUST specify which row in tableA you wish to join to. 然后,您必须指定要加入tableA中的哪一行。 If there are more than one row in the other table, How can the query processor know which one you want ? 如果另一张表中有多行,查询处理器如何知道您要哪一行?

If you want the one with the lowest value of name , then you might do this: 如果要使用name值最低的那个,则可以这样做:

Select * from tableB b
    join tableA a
       on a.id = b.Id
          and a.name =
             (Select min(name) from tableA
              where id = b.id)

but even that won't work if there multiple rows with the same values for both id AND name . 但是即使有多个行的id AND name具有相同的值,即使这样也行不通。 What you might really need is a Primary Key on tableA. 您可能真正需要的是tableA上的主键。

Use: 采用:

select
  a.id,
  a.name,
  b.amount
from
   (select
      id,
      name,
      row_number() over (partition by id order by name) as rn
      from tablea) a
left join (
    select
      id,
      amount,
      row_number() over (partition by id order by amount) as rn
    from tableb) b
  on a.id = b.id
    and a.rn = b.rn
order by a.id, a.name

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM