2015-05-27 45 views
3

我有两个表:MyOrders和MyDrivers。SQL Server - 将Table1连接到Table2 ON子串(T1.Field)= T2.ID

在表MyOrders,我有一个名为详细列(数据类型TEXT - 我知道,但我没有建立数据库...)

在MyOrders.Details,有时有逗号分隔的列表与MyDrivers表的ID值对应的数值。

目标是使用这些列表将MyOrders加入MyDrivers。

例如:

CREATE TABLE MyOrders 
(
MyOrderID INT IDENTITY, 
Details TEXT -- Wish it were NVarchar, but what can I do... 
) 
GO 

CREATE TABLE MyDrivers 
(
MyDriverID INT IDENTITY, 
DriverName NVARCHAR(50) 
) 
GO 

INSERT INTO MyOrders (Details) VALUES ('1,3,5,7,9') 
INSERT INTO MyOrders (Details) VALUES ('2,4,6,8') 
INSERT INTO MyOrders (Details) VALUES ('1,2,3,4') 
INSERT INTO MyOrders (Details) VALUES ('4,5,6,7,8') 
INSERT INTO MyOrders (Details) VALUES (NULL) 
INSERT INTO MyOrders (Details) VALUES ('') 
INSERT INTO MyOrders (Details) VALUES ('9') 

INSERT INTO MyDrivers (DriverName) VALUES ('Alex') 
INSERT INTO MyDrivers (DriverName) VALUES ('Bobby') 
INSERT INTO MyDrivers (DriverName) VALUES ('Carl') 
INSERT INTO MyDrivers (DriverName) VALUES ('Daryl') 
INSERT INTO MyDrivers (DriverName) VALUES ('Ed') 
INSERT INTO MyDrivers (DriverName) VALUES ('Frank') 
INSERT INTO MyDrivers (DriverName) VALUES ('George') 
INSERT INTO MyDrivers (DriverName) VALUES ('Hal') 
INSERT INTO MyDrivers (DriverName) VALUES ('Ichabod') 
INSERT INTO MyDrivers (DriverName) VALUES ('Justin Timberlake') 

SELECT * FROM MyOrders O 
INNER JOIN MyDrivers D 
    ON D.MyDriverID = ...? substring()? patindex()? 
WHERE O.MyOrderID = 1 

这里所期望的结果是,对于MyOrderID 1,我会收到5行的结果:一个用于每个在该详细列表分配给该命令的五个驱动的相同的顺序。如果没有列表(NULL,'','',''),那么我不希望返回任何行。 **有时用户删除这个字段中的值并留下空格,所以我假设我将不得不使用TRIM。但他们总是添加必要的逗号,所以至少有...

我不知道如何去做这件事;我仍然需要学习很多SQL。任何有用的提示/想法将不胜感激。

非常感谢您提前!

回答

2

您可以使用 IN这样的:

SELECT * 
FROM MyOrders O 
INNER JOIN MyDrivers D 
ON ',' + CAST(D.MyDriverID as varchar) +',' IN(','+ ISNULL(O.Details, '') +',') 
WHERE O.MyOrderID = 1 

更新
其实,你不能使用IN,但你可以使用LIKE。原因是IN需要一个值列表,而不是用逗号分隔的单个字符串值。

SELECT MyOrderID, MyDriverID, DriverName 
FROM MyOrders O 
INNER JOIN MyDrivers D 
ON ','+ cast(ISNULL(O.Details, '') as varchar(max)) +',' LIKE 
    '%,' + CAST(D.MyDriverID as varchar) +',%' 
WHERE O.MyOrderID = 1 

使用wewesthemenacehis answer提供的小提琴,我测试过他的建议的解决方案(分割字符串)VS我建议的解决方案(像)的性能。似乎使用like比样本数据更快(少于一半的时间)(如果数据不同,可能会得到不同的结果)。您可以自己在this link中查看。

如果可能,我会强烈建议更改数据库结构并创建另一个表来保存当前存储在“详细信息”列中的值。

+0

我选择这个答案* THE *回答它的简单。对于提供的示例数据,此解决方案似乎工作得更快一些,但只有几毫秒。然而,我指出@wewesthemenace提供的答案也很有用,它提供了一个永久性函数,可以在类似实例中使用而不必重写查询,这显然是一个学习点。感谢你们的回应! – 3BK

2

首先,你需要一个分割器功能来分割你的逗号分隔值。 Jeff Moden写的DelmitedSplitN4K函数是其中最快的分离器之一。阅读article了解更多信息。

CREATE FUNCTION [dbo].[DelimitedSplitN4K](
    @pString NVARCHAR(4000), 
    @pDelimiter NCHAR(1) 
) 
RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 

WITH E1(N) AS (
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
), 
E2(N) AS (SELECT 1 FROM E1 a, E1 b), 
E4(N) AS (SELECT 1 FROM E2 a, E2 b), 
cteTally(N) AS(
    SELECT TOP (ISNULL(DATALENGTH(@pString)/2,0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
), 
cteStart(N1) AS (
    SELECT 1 UNION ALL 
    SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
), 
cteLen(N1,L1) AS(
    SELECT s.N1, 
     ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,4000) 
    FROM cteStart s 
) 
SELECT 
    ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
    Item  = SUBSTRING(@pString, l.N1, l.L1) 
FROM cteLen l 
; 

然后,您想先分割MyOrders.Details中的值。分开后,你的执行JOIN以达到预期的效果:

WITH CteSplitted AS(
    SELECT 
     mo.MyOrderID, 
     CAST(s.Item AS INT) AS DriverID 
    FROM MyOrders mo 
    CROSS APPLY dbo.DelimitedSplitN4K(CONVERT(NVARCHAR(4000), mo.Details), ',') s 
) 
SELECT * 
FROM CteSplitted cs 
INNER JOIN MyDrivers d 
    ON d.MyDriverID = cs.DriverID 
WHERE cs.MyOrderID = 1 

SQL Fiddle

结果

| MyOrderID | DriverID | MyDriverID | DriverName | 
|-----------|----------|------------|------------| 
|   1 |  1 |   1 |  Alex | 
|   1 |  3 |   3 |  Carl | 
|   1 |  5 |   5 |   Ed | 
|   1 |  7 |   7 |  George | 
|   1 |  9 |   9 | Ichabod | 
+0

谢谢你的repsonse。尽管我最终选择了其他答案,但您的解决方案也非常适合在行动中看到,并且在将来肯定会有用。我非常感谢你的时间。再次感谢! – 3BK

+0

@ 3BK,没问题的人。我很高兴我能帮上忙。 –

相关问题