我正在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
答案 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
如果给定值为ISNULL
(SQL 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{}