对多个联接使用合并

时间:2018-07-13 04:29:31

标签: sql sql-server

我正在SQL Server中创建一个报表视图。我需要从表的两列中选择数据。每列都有FK到两个单独的表。两列之间只能有一个值。相应表的FK标识符或空值。作为一个人,不能同时扮演两个角色。

dbo.Personnel

Name |  InternalRoleID | ExternalRoleID
-----+-----------------+----------------
John |       3         |      Null
Bob  |       Null      |      3
Rick |       5         |      Null
Anna |       6         |      Null

dbo.InternalRoles

ID | Name
---+------------------------------
3  |  Accountant
3  |  Manager
5  |  Supervisor
6  |  Worker

dbo.ExternalRoles

ID | Name
---+------------------------------
3  |  Delivery Driver
3  |  Cleaner
5  |  Electrician
6  |  Auditor

任何人都可以协助使用最佳查询。我已经尝试过合并,但是我不确定这是否是最有效的方法。

它是另一系列查询的一部分,将显示为[RoleName]:

Name | RoleName      | Location | TimeonSite
-----+---------------+----------+------------
John | Accountant    |    A     |    Null
Bob  | Manager       |    B     |     4
Rick | Electrician   |    C     |     2
Anna | Supervisor    |    C     |    33

4 个答案:

答案 0 :(得分:2)

请尝试以下查询。由于您具有相同ID(Id 3)的多个内部和外部角色,因此将导致具有相同名称“ John”和“ Bob”的多个记录。如果那不是您想要的,请告诉我您希望显示哪个。

CREATE TABLE #Personnel
    (
        Name VARCHAR(100) ,
        InternalRoleID INT ,
        ExternalRoleID INT
    );

CREATE TABLE #InternalRoles
    (
        ID INT ,
        Name VARCHAR(100)
    );

CREATE TABLE #ExternalRoles
    (
        ID INT ,
        NAme VARCHAR(100)
    );

INSERT INTO #Personnel
VALUES ( 'John', 3, NULL ) ,
       ( 'Bob', NULL, 3 ) ,
       ( 'Rick', 5, NULL ) ,
       ( 'Anna', 6, NULL );


INSERT INTO #InternalRoles ( ID ,
                             Name )
VALUES ( 3, 'Accountant' ) ,
       ( 3, 'Manager' ) ,
       ( 5, 'Supervisor' ) ,
       ( 6, 'Worker' );



INSERT INTO #ExternalRoles ( ID ,
                             NAme )
VALUES ( 3, 'Delivery Driver' ) ,
       ( 3, 'Cleaner' ) ,
       ( 5, 'Electrician' ) ,
       ( 6, 'Auditor' );


SELECT P.Name ,
       COALESCE(IR.Name, ER.NAme) AS RoleName
FROM   #Personnel P
       LEFT JOIN #InternalRoles IR ON P.InternalRoleID = IR.ID
       LEFT JOIN #ExternalRoles ER ON P.ExternalRoleID = ER.ID;

DROP TABLE #ExternalRoles;
DROP TABLE #Personnel;
DROP TABLE #InternalRoles;

答案 1 :(得分:0)

有几种方法可以解决此问题:

  • 使用COALESCE返回第一个非NULL值(SQL Fiddle

    SELECT Personnel.Name, COALESCE(InternalRoles.Name, ExternalRoles.Name, 'Unknown') AS RoleName
    FROM Personnel
    LEFT OUTER JOIN InternalRoles ON InternalRoles.ID = Personnel.InternalRoleID AND Personnel.ExternalRoleID IS NULL
    LEFT OUTER JOIN ExternalRoles ON ExternalRoles.ID = Personnel.ExternalRoleID AND Personnel.InternalRoleID IS NULL
  • 如果给定值为ISNULLSQL Fiddle),请使用NULL返回第二个值

    SELECT Personnel.Name, ISNULL(InternalRoles.Name, ExternalRoles.Name) AS RoleName
    FROM Personnel
    LEFT OUTER JOIN InternalRoles ON InternalRoles.ID = Personnel.InternalRoleID AND Personnel.ExternalRoleID IS NULL
    LEFT OUTER JOIN ExternalRoles ON ExternalRoles.ID = Personnel.ExternalRoleID AND Personnel.InternalRoleID IS NULL
  • 使用CASE语句定义if-then-else行为(SQL Fiddle

    SELECT Personnel.Name, CASE WHEN Personnel.InternalRoleID IS NOT NULL THEN InternalRoles.Name ELSE ExternalRoles.Name END AS RoleName
    FROM Personnel
    LEFT OUTER JOIN InternalRoles ON InternalRoles.ID = Personnel.InternalRoleID AND Personnel.ExternalRoleID IS NULL
    LEFT OUTER JOIN ExternalRoles ON ExternalRoles.ID = Personnel.ExternalRoleID AND Personnel.InternalRoleID IS NULL

实际上,您唯一需要考虑的就是最适合您查询风格的因素,因为所有这些都具有相同的执行计划和相对相同的执行时间。就个人而言,我建议使用COALESCE,因为如果您愿意,它可以在您的Internal / ExternalRoles表中的Name值之一恰好为NULL的情况下显示默认值。

答案 2 :(得分:0)

或者,您可以尝试以下操作:

select [Name],
       coalesce((select [Name] from InternalRoles where id = p.InternalRoleId),
                (select [Name] from ExternalRoles where id = p.ExternalRoleId)) [RoleNamE]
from Personnel p

答案 3 :(得分:0)

尝试一下:-用例

int -> interface{}