使用int列连接nvarchar(max)列的SQL

时间:2017-05-03 14:11:52

标签: sql-server

我需要一些专家帮助才能在nvarchar(max)列上使用int列进行左联接。我有一个Company表,EmpIDnvarchar(max),此列包含多个以逗号分隔的员工ID:

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 

如果在单独的列中有多个empID,我的要求是获取所有empName。非常感谢任何有价值的投入。

3 个答案:

答案 0 :(得分:1)

如果可能,您应该规范化您的数据库 阅读Is storing a delimited list in a database column really that bad?,你会看到很多理由为什么这个问题的答案是绝对是的!

但是,如果您无法更改数据库结构,则可以使用LIKE:

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 + ',%'

答案 1 :(得分: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

答案 2 :(得分: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