我有两个SQL表EmployeeMst和EmployeeCity
EmployeeMst
SrNo Name
1 abc
2 xyz
3 pqr
4 def
EmployeeCity
srno City EmplSrNo
1 Delhi 1,2,3,4
2 Mumbai 2,3,1
3 New York 3,2
我想从EmployeeMst获取具有选择查询的员工姓名
输出如下:
srno City EmployeeName
1 Delhi abc,xyz,pqr,def
2 Mumbai xyz,pqr,abc
3 New York pqr,xyz
此表中有几个数据。请告诉我如何才能这样做
我使用charindex
,但需要更多时间。
答案 0 :(得分:5)
我仍然认为无论桌子是旧的还是新的,你都应该花时间尽快修复糟糕的设计。你只是在推迟不可避免的事情。因此,这可以帮助您开始规范化设计:
-- CREATE CITY TABLE
CREATE TABLE dbo.City
(
SrNo INT,
City VARCHAR(50)
);
-- POPULATE FROM EXISTING TABLE
INSERT dbo.City (SrNo, City)
SELECT SrNo, City
FROM dbo.EmployeeCity;
-- CREATE CITY-EMPLOYEE JUNCTION TABLE USING EXISTING
-- DATA, AND XML METHOD TO SPLIT COMMA SEPARATED VALUES
-- INTO ROWS
CREATE TABLE dbo.EmployeeCity2 (CitySrNo, EmployeeSrNo)
SELECT SrNo, i.value('.', 'INT')
FROM ( SELECT SrNo,
x = CONVERT(XML, '<i>' +
REPLACE(EmplSrNo, ',', '</i><i>') +
'</i>')
FROM dbo.EmployeeCity
) AS t
CROSS APPLY t.x.nodes('i') rx (i);
-- DROP EXISTING TABLE SO THAT WE CAN CREATE A VIEW OF THE SAME NAME
DROP TABLE dbo.EmployeeCity;
GO
-- CREATE A VIEW THAT REPLICATES THE FORMAT OF THE CURRENT TABLE SO
-- THAT EXISTING SELECT QUERIES ARE NOT AFFECTED
CREATE VIEW dbo.EmployeeCity
AS
SELECT c.SrNo,
c.City,
EmplSrNo = STUFF(( SELECT ',' + CAST(EmployeeSrNo AS VARCHAR(10))
FROM dbo.EmployeeCity2 AS ec
WHERE ec.CitySrNo = c.SrNo
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)'), 1, 1, '')
FROM dbo.City AS c;
GO
-- FINALLY, THE QUERY YOU NEED TO GET THE OUTPUT IN THE QUESTION
SELECT c.SrNo,
c.City,
EmployeeName = STUFF(( SELECT ',' + m.Name
FROM dbo.EmployeeCity2 AS ec
INNER JOIN EmployeeMst AS m
ON m.SrNo = ec.EmployeeSrNo
WHERE ec.CitySrNo = c.SrNo
FOR XML PATH(''), TYPE
).value('.', 'VARCHAR(MAX)'), 1, 1, '')
FROM dbo.City AS c;
您仍然需要修改数据的插入/更新/删除方式,但是发生这种情况的位置应该比选择的位置少得多,并且视图会覆盖您现有的所有选择查询。
要进一步阅读上面使用的几个原则来分割逗号分隔的字符串,然后再将它重新组合在一起,请参阅:
答案 1 :(得分:2)
使用它。的 Fiddler Demo 强>
CREATE FUNCTION EmployeeName(@Expr1 AS VARCHAR(MAX))
RETURNS VARCHAR(MAX)
BEGIN
DECLARE @res AS VARCHAR(MAX)
SET @res = (SELECT ',' + B.name AS A FROM
(SELECT
Split.a.value('.', 'VARCHAR(100)') AS CVS
FROM
(
SELECT CAST ('<M>' + REPLACE(@Expr1, ',', '</M><M>') + '</M>' AS XML) AS CVS
) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a)) AS A
INNER JOIN EmployeeMst AS B ON A.CVS = B.id
FOR XML PATH(''), TYPE).value('.', 'varchar(max)')
RETURN STUFF(@res, 1,1,'')
END
SELECT srno, city, dbo.EmployeeName(EmplSrNo) AS EmployeeName FROM EmployeeCity
答案 2 :(得分:1)
[SQL Fiddle][1]
--------------------------------------------------------
--create temp table for using in split
IF OBJECT_ID('tempdb..#Tally') IS NOT NULL
DROP TABLE #Tally
CREATE TABLE #Tally ( N INT )
DECLARE @i AS INT = 1
WHILE @i != 1000
BEGIN
INSERT INTO #Tally
( N )
VALUES ( @i )
SET @i = @i + 1
END
--------------------------------------------------------
--Create temp table EmployeeMst
IF OBJECT_ID('tempdb..#EmployeeMst') IS NOT NULL
DROP TABLE #EmployeeMst
CREATE TABLE #EmployeeMst
(
SrNo INT ,
EmpNo VARCHAR(10),
)
INSERT INTO #EmployeeMst
VALUES ( 1, 'abc' ),
( 2, 'xyz' ),
( 3, 'pqr' ),
( 4, 'def' )
--------------------------------------------------------
--Create temp table EmployeeCity
IF OBJECT_ID('tempdb..#EmployeeCity') IS NOT NULL
DROP TABLE #EmployeeCity
CREATE TABLE #EmployeeCity
(
srno INT ,
City VARCHAR(20) ,
EmplSrNo VARCHAR(MAX)
)
INSERT INTO #EmployeeCity
VALUES ( 1, 'Delhi', '1,2,3,4' ),
( 2, 'Mumbai', '2,3,1' ),
( 3, 'New York', '3,2' )
--------------------------------------------------------
--Get output as in example
;
WITH EmployeeCityUpdated
AS ( SELECT E.srno ,
E.City ,
CONVERT(INT, REPLACE(f4.EmpNoUpd, ',', '')) AS EmployeeName
FROM #EmployeeCity AS E
JOIN #Tally AS T ON SUBSTRING(',' + E.EmplSrNo, T.N, 1) = ','
AND T.N < LEN(EmplSrNo) + 1
CROSS APPLY ( SELECT string = SUBSTRING(' '
+ EmplSrNo + ',',
T.N + 1,
LEN(EmplSrNo)
+ 1)
) f1
CROSS APPLY ( SELECT p1 = CHARINDEX(',', string)
) f2
CROSS APPLY ( SELECT EmpNoUpd = SUBSTRING(EmplSrNo,
T.N, p1)
) f4
)
SELECT EC.srno ,
EC.City ,
SUBSTRING(( SELECT ',' + CONVERT(VARCHAR, EM.EmpNo)
FROM EmployeeCityUpdated AS ECU
JOIN #EmployeeMst AS EM ON ECU.EmployeeName = EM.SrNo
WHERE ECU.srno = EC.srno
FOR
XML PATH('')
), 2, 1000) AS EmployeeName
FROM #EmployeeCity AS EC
--------------------------------------------------------
--srno City EmployeeName
--1 Delhi abc,xyz,pqr,def
--2 Mumbai xyz,pqr,abc
--3 New York pqr,xyz