【问题标题】:How can I select only the first record with each foreign key in SQL Server?如何仅选择 SQL Server 中每个外键的第一条记录?
【发布时间】:2012-04-03 10:09:42
【问题描述】:

我在联系人详细信息数据库中有如下所示的行:

contactID - bioID - AddressLine1 - City 
393         1       1 nowhere st   toronto
3921        1       2 somewhere st vancouver
3231        2       1 anywhere rd  barrie
1122        2       2 overthere st halifax      

我目前正在将其加入到包含 firstname, lastname 等列的生物表中,结果如下所示:

bioid    firstname    lastname    addressline1    city
1        some         guy         1 nowhere st    toronto
1        some         guy         2 somewhere st  vancouver
2        that         girl        1 anywhere rd   barrie
2        that         girl        2 overthere st  halifax

所以我基本上为每个简历获得 2 行。无论如何我可以像这样选择这一切作为一行:

bioid    firstname    lastname   addressline1x1   cityx1    addressline1x2    cityx2
1        some         guy        1 nowhere st     toronto   2 somewhere st    vancouver
2        that         girl       1 anywhere rd    barrie    2 overthere st    halifax

感谢任何帮助。

谢谢, 托马斯

编辑:

非常感谢丹尼斯和贾斯汀,我能够解决这个问题。但是,现在我有另一个。

我想实际选择地址作为 1 个字段,例如:

bioid    firstname    lastname    primary address         secondary address
1        some         guy         1 nowhere st, toronto   2 somewhere st, vanvouver
2        that         girl        1 anywhere rd, barrie   2 overthere st, halifax

我知道我可以通过连接如下列来做到这一点:

cd1.addressline1 + ', ' cd1.city AS 'Primary Address' 

但是,记录中的某些字段是空的,例如,如果没有辅助地址 - 那么我怎样才能使辅助地址不输出','?这些字段是空字符串,而不是 NULL 值。

再次感谢!

编辑:我有这个工作使用:

STUFF(COALESCE(', ' + NULLIF(C1.[AddressLine1], ''), '') + 
  COALESCE(', ' + NULLIF(C1.[AddressLine2], ''), '') + 
  COALESCE(', ' + NULLIF(C1.[City], ''), '') + 
  COALESCE(', ' + NULLIF(C1.[State], ''), '') + 
  COALESCE(', ' + NULLIF(C1.[Country], ''), '') + 
  COALESCE(', ' + NULLIF(C1.[ZipCode], ''), ''),1, 1, '') AS 'Primary Address'

【问题讨论】:

    标签: sql sql-server sql-server-2005 join


    【解决方案1】:
    ;with cd as(
    select *, rn = dense_rank(partition by bioid order by addressline, city)
    from ContactDetails cd
    )
    select c.bioid, c.firstname, c.lastname, cd1.AddressLine, cd1.City, cd2.AddressLine, cd2.City, cd3.AddressLine, cd3.City
    from Contact c 
    left join cd cd1 on c.bioid = cd1.bioid and cd1.rn = 1
    left join cd cd2 on c.bioid = cd2.bioid and cd2.rn = 2
    left join cd cd3 on c.bioid = cd3.bioid and cd3.rn = 3
    

    【讨论】:

    • 这只有在他假设只有 3 个地址时才有效。如果还有更多,那么他将丢失数据。
    • @JustinPihony OP 只要求提供 2 个地址,我给了他 3 个地址和添加更多地址的方法。 :)
    • 是的,OP在示例数据中说有2个,但这不一定是要求
    • @JustinPihony 不要考虑斑马
    • @JustinPihony 你可以随时添加dense_rank(partition by bioid order by city, addressline) 我将在我的脚本中这样做
    【解决方案2】:

    您可以尝试PIVOT TABLERECURSIVE CTE。如果您知道用户将拥有多少个地址,则数据透视表将起作用(但是,如果您知道您也可以对其进行硬编码:)),CTE 将适用于未知数量的地址,但是,它不会创建多个列,而不是一个逗号分隔的列表。

    无论采用哪种方式,您都可能需要使用ROW_NUMBER 来创建唯一性顺序。

    这应该是递归 CTE 的一个工作示例:

    SELECT *, ROW_NUMBER() OVER(PARTITION BY bioid ORDER BY contactid) AS rownum
    INTO #TableToRecurse
    FROMContactDetails
    
    ;WITH FinalOutput AS
    (
    --Anchor row of recursion
    SELECT bioid, firstname, lastname, addressline, city, rownum
    FROM #TableToRecurse 
    WHERE rownum = 1
    UNION ALL 
    --Recursion piece
    SELECT tr.bioid, tr.firstname, tr.lastname, 
        FinalOutput.addressline + ', ' + tr.addressline, FinalOutput.city + ', ' + tr.city, tr.rownum
    FROM #TableToRecurse AS tr
        JOIN FinalOutput
            ON  FinalOutput.bioid = tr.bioid AND FinalOutput.rownum = tr.rownum +1
    )
    --Final output only showing the last row (Max)
    --Which should have everything concatenated together
    SELECT FinalOutput.bioid, FinalOutput.firstname, FinalOutput.lastname, 
        FinalOutput.addressline, FinalOutput.city
    FROM FinalOutput 
        JOIN 
        (
            SELECT MAX(rownum) AS MaxRowNum, bioid
            FROM FinalOutput
            GROUP BY bioid
        ) AS MaxForEach
            ON FinalOutput.bioid = MaxForEach.bioid 
                AND FinalOutput.rownum = MaxForEach.MaxRowNum
    

    【讨论】:

    • PIVOT 会起作用,但PIVOT 的作用并不明显。可以为此使用ROW_NUMBER
    • 是的,我在想,但忘了把它记下来。谢谢,已经更新了。
    • 有什么值得期待的例子吗?
    • 递归选择中不应该是tr.rownum + 1吗?
    • 非常感谢您的意见,非常感谢!我最终使用了下面的示例,因为我知道只有 2 条记录/bioID,而且他有一个更快的示例,我能够很容易地集成到一个 500 行的大型存储过程中。
    【解决方案3】:
     SELECT *
        FROM   Table_1 t 
    
        SELECT *
    FROM   Table_1 t 
    
    SELECT af.bioid,
           af.fname,
           af.lastname,
           address1,
           city1,
           address2,
           tbl2,
           rrr
    FROM   (
               SELECT tbl1.bioid,
                      tbl1.fname,
                      tbl1.lastname,
                      tbl1.addressline1 AS address1,
                      tbl1.city AS city1,
                      tbl2.addressline1 AS address2,
                      tbl2.city AS tbl2,
                      ROW_NUMBER() OVER(PARTITION BY tbl1.bioid ORDER BY tbl1.bioid) AS 
                      rrr
               FROM   Table_1 tbl1,
                      Table_1 tbl2
               WHERE  tbl1.bioid = tbl2.bioid
                        AND tbl1.addressline1+tbl1.city <> tbl2.addressline1+tbl2.city
           ) af
    WHERE  af.rrr = 1
    

    【讨论】:

    • 如果您在不同城市有相同的地址怎么办?您的查询不会返回那个人。如果那个人没有联系方式怎么办?
    • @DenisValeev 我给了他一种方法。如果它更好或最好 - 我相信可以有更好的解决方案(总是有更好的解决方案) - 但他可以得到这个想法并从这里继续。
    • OP 说了两个表,一个是 ContactDetails,另一个是 Bio;据我所知,你只有一个
    • 我同意提供一半的答案总是更好。
    猜你喜欢
    • 2021-12-30
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多