2017-05-03 82 views
1

我需要一些專家幫助來對nvarchar(max)列加上int列。我有一個CompanyEmpIDnvarchar(max)與此列保存多個員工的ID以逗號分隔:要加入nvarchar(max)列與int列的SQL語句

1221,2331,3441 

我想與Employee表,其中EmpIDint加入此列。

我做了類似下面的事情,但是當我有3個empId或1個empID時,這不起作用。

SELECT 
    A.*, B.empName AS empName1, D.empName AS empName2 
FROM 
    [dbo].[Company] AS A 
LEFT JOIN 
    [dbo].[Employee] AS B ON LEFT(A.empID, 4) = B.empID 
LEFT JOIN 
    [dbo].[Employee] AS D ON RIGHT(A.empID, 4) = D.empID 

我的要求是獲取所有empNames,如果有多個empID在單獨的列中。非常感謝任何寶貴的意見。

+0

所以,你要的連接成功,如果有*逗號分隔值中的任何*匹配? – JosephStyons

+3

您應該永遠不要將多個值放入一列!這是非常糟糕的設計,甚至違反了數據庫設計的第一種正常形式**。 ***不要做!***你只會有悲傷和雜亂的代碼和心痛 - 如果你需要「公司」和「員工」之間的關係,你應該有**單獨的**處理和模擬這個表格 - ***這是正確的關係方式***做到這一點 –

+1

^marc_s說什麼。 –

回答

0

你可以給STRING_SPLIT一槍。

的SQL Server(從2016)

https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql

CREATE TABLE #Test 
(
RowID INT IDENTITY(1,1), 
EID INT, 
Names VARCHAR(50) 
) 

INSERT INTO #Test VALUES (1,'John') 
INSERT INTO #Test VALUES (2,'James') 
INSERT INTO #Test VALUES (3,'Justin') 
INSERT INTO #Test VALUES (4,'Jose') 
GO 

CREATE TABLE #Test1 
(
RowID INT IDENTITY(1,1), 
ID VARCHAR(MAX) 
) 

INSERT INTO #Test1 VALUES ('1,2,3,4') 
GO 

SELECT Value,T.* FROM #Test1 
CROSS APPLY STRING_SPLIT (ID , ',') 
INNER JOIN #Test T ON value = EID 
+0

不錯。這確實需要sql 2016。 https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql – JosephStyons

1

如果可能的話,您應該規範化您的數據庫。
閱讀Is storing a delimited list in a database column really that bad?,你會看到很多原因爲什麼這個問題的答案是絕對是!

但是,如果您不能更改數據庫結構,你可以使用這樣的:

SELECT A.*, B.empName AS empName1, D.empName AS empName2 
FROM [dbo].[Company] AS A 
LEFT JOIN [dbo].[Employee] AS B ON ',' + A.empID + ',' LIKE '%,'+ B.empID + ',%' 
0

這聽起來像你需要一個表以正式的方式向員工鏈接到企業。如果你有這個,這將是微不足道的。事實上,這很麻煩,而且速度很慢。下面的腳本爲你創建了這個鏈接。如果你真的想保持你當前的結構(壞主意),那麼你想要的部分是在「插入...」塊。

--clean up the results of any prior runs of this test script 
if object_id('STACKOVERFLOWTEST_CompanyEmployeeLink') is not null 
    drop table STACKOVERFLOWTEST_CompanyEmployeeLink; 
if object_id('STACKOVERFLOWTEST_Employee') is not null 
    drop table STACKOVERFLOWTEST_Employee; 
if object_id('STACKOVERFLOWTEST_Company') is not null 
    drop table STACKOVERFLOWTEST_Company; 
go 

--create two example tables 
create table STACKOVERFLOWTEST_Company 
(
    ID int 
,Name nvarchar(max) 
,EmployeeIDs nvarchar(max) 
,primary key(id) 
) 
create table STACKOVERFLOWTEST_Employee 
(
    ID int 
,FirstName nvarchar(max) 
,primary key(id) 
) 

--drop in some test data 
insert into STACKOVERFLOWTEST_Company values(1,'ABC Corp','1,2,3,4,50') 
insert into STACKOVERFLOWTEST_Company values(2,'XYZ Corp','4,5,6,7,8')--note that annie(#4) works for both places 
insert into STACKOVERFLOWTEST_Employee values(1,'Bob') --bob works for abc corp 
insert into STACKOVERFLOWTEST_Employee values(2,'Sue') --sue works for abc corp 
insert into STACKOVERFLOWTEST_Employee values(3,'Bill') --bill works for abc corp 
insert into STACKOVERFLOWTEST_Employee values(4,'Annie') --annie works for abc corp 
insert into STACKOVERFLOWTEST_Employee values(5,'Matthew') --Matthew works for xyz corp 
insert into STACKOVERFLOWTEST_Employee values(6,'Mark')  --Mark works for xyz corp 
insert into STACKOVERFLOWTEST_Employee values(7,'Luke')  --Luke works for xyz corp 
insert into STACKOVERFLOWTEST_Employee values(8,'John')  --John works for xyz corp 
insert into STACKOVERFLOWTEST_Employee values(50,'Pat')  --Pat works for XYZ corp 

--create a new table which is going to serve as a link between employees and their employer(s) 
create table STACKOVERFLOWTEST_CompanyEmployeeLink 
(
    CompanyID int foreign key references STACKOVERFLOWTEST_Company(ID) 
,EmployeeID INT foreign key references STACKOVERFLOWTEST_Employee(ID) 
) 

--this join looks for a match in the csv column. 
--it is horrible and slow and unreliable and yucky, but it answers your original question. 
--drop these messy matches into a clean temp table 
--this is now a formal link between employees and their employer(s) 
insert into STACKOVERFLOWTEST_CompanyEmployeeLink 
select c.id,e.id 
from 
    STACKOVERFLOWTEST_Company c 
    --find a match based on an employee id followed by a comma or preceded by a comma 
    --the comma is necessary so we don't accidentally match employee "5" on "50" or similar 
    inner join STACKOVERFLOWTEST_Employee e on 
     0 < charindex(  convert(nvarchar(max),e.id) + ',',c.employeeids) 
    or 0 < charindex(',' + convert(nvarchar(max),e.id)  ,c.employeeids) 
order by 
    c.id, e.id 

--show final results using the official linking table 
select 
    co.Name as Employer 
,emp.FirstName as Employee 
from 
    STACKOVERFLOWTEST_Company co 
    inner join STACKOVERFLOWTEST_CompanyEmployeeLink link on link.CompanyID = co.id 
    inner join STACKOVERFLOWTEST_Employee emp on emp.id = link.EmployeeID