我有三个Excel工作表,我将它们推入SQL Server中的表中,我需要加入这些表。但是,我相信-正如我已经尝试过的-普通加入将不起作用。我有编程背景,但是对SQL没有那么了解。
Table1
ID Data_column reference_number
1 some data 1528,ss-456
2 some data 9523
3 some data ss-952
4 some data null
Table2
ID Data_column
ss-456 some data
ss-952 some data
Table3
ID Data_column
1528 some data
9523 some data
在下面的情况下,我将如何在两个表上加入此原始数据。
Table1
ID Data_column reference_number
1 some data 1528,ss-456
答案 0 :(得分:2)
declare @t1 as table(
id int
,data_column varchar(20)
,reference_number varchar(20)
)
declare @t2 as table(
id varchar(20)
,data_column varchar(20)
)
declare @t3 as table(
id varchar(20)
,data_column varchar(20)
)
insert into @t1 values(1,'some data','1528,ss-456'),(2,'some data','9523'),(3,'some data','ss-952'),(4,'some data',null);
insert into @t2 values('ss-456','some data'),('ss-952','some data');
insert into @t3 values(1528,'some data'),(9523,'some data');
快速解决方案
select * from @t1 t1
left outer join @t2 t2 on t1.reference_number like '%'+t2.id or t1.reference_number like t2.id+'%'
left outer join @t3 t3 on t1.reference_number like '%'+t3.id or t1.reference_number like t3.id+'%'
结果(左联接):
id data_column reference_number id data_column id data_column
1 some data 1528,ss-456 ss-456 some data 1528 some data
2 some data 9523 NULL NULL 9523 some data
3 some data ss-952 ss-952 some data NULL NULL
4 some data NULL NULL NULL NULL NULL
您可以将“左外部连接”更改为“内部连接”以实现完全匹配。
答案 1 :(得分:1)
笨拙的设计,笨拙的解决方案:
SELECT *
FROM Table1
INNER JOIN Table2 ON ',' + Table1.reference_number + ',' LIKE '%,' + Table2.ID + ',%'
INNER JOIN Table3 ON ',' + Table1.reference_number + ',' LIKE '%,' + Table3.ID + ',%'
您 必须 附加前导和尾随逗号,以确保例如1528,ss-456asdf
与%ss-456%
不匹配。
答案 2 :(得分:0)
我在这里看到两个问题。首先是表2和3中ID的不一致类型和表1中所引用密钥的聚合。这是解决这两个问题的示例。为了拆分REFERENCE_NUMBER列,我使用了STRING_SPLIT函数。
更新: 我添加了适用于SQL Server 2012的解决方案。
我假设您希望将表1中的数据与2或3连接起来,具体取决于此数据的存在。这只是我的想法,您想要达到的目标。
-- data preparing
declare @t1 as table(
id int
,data_column varchar(20)
,reference_number varchar(20)
)
declare @t2 as table(
id varchar(20)
,data_column varchar(20)
)
declare @t3 as table(
id int
,data_column varchar(20)
)
insert into @t1 values(1,'some data','1528,ss-456'),(2,'some data','9523'),(3,'some data','ss-952'),(4,'some data',null);
insert into @t2 values('ss-456','some data'),('ss-952','some data');
insert into @t3 values(1528,'some data'),(9523,'some data');
-- Solution example version >= 2016
with base as (
select t1.id,t1.data_column,f1.value from @t1 t1 outer apply string_split(t1.reference_number,',') f1)
select b.id,b.data_column,b.value,t2.data_column from base b join @t2 t2 on b.value = t2.id
union all
select b.id,b.data_column,b.value,t3.data_column from base b join @t3 t3 on try_cast(b.value as int ) = t3.id
union all
select b.id,b.data_column,b.value,null from base b where b.value is null;
-- Solution for SQL Version < 2016
with base as (
select t1.id,t1.data_column,f1.value from @t1 t1 outer apply(
SELECT Split.a.value('.', 'NVARCHAR(MAX)') value
FROM
(
SELECT CAST('<X>'+REPLACE(t1.reference_number, ',', '</X><X>')+'</X>' AS XML) AS String
) AS A
CROSS APPLY String.nodes('/X') AS Split(a)
) f1)
select b.id,b.data_column,b.value,t2.data_column from base b join @t2 t2 on b.value = t2.id
union all
select b.id,b.data_column,b.value,t3.data_column from base b join @t3 t3 on try_cast(b.value as int ) = t3.id
union all
select b.id,b.data_column,b.value,null from base b where b.value is null;
答案 3 :(得分:0)
您将需要一个函数来将逗号分隔的字符串分成几行。如果您无权访问内置string_split() function(从mssql 2017开始,兼容性为130),则可以选择here
CREATE TABLE table1( ID INTEGER NOT NULL PRIMARY KEY ,Data_column VARCHAR(10) NOT NULL ,reference_number VARCHAR(11) );
INSERT INTO table1(ID,Data_column,reference_number) VALUES (1,'t1somedata','1528,ss-456') , (2,'t1somedata','9523') , (3,'t1somedata','ss-952') , (4,'t1somedata',NULL);
CREATE TABLE table2( ID VARCHAR(6) NOT NULL PRIMARY KEY ,Data_column VARCHAR(10) NOT NULL );
INSERT INTO table2(ID,Data_column) VALUES ('ss-456','t2somedata'), ('ss-952','t2somedata');
CREATE TABLE table3( ID VARCHAR(6) NOT NULL PRIMARY KEY ,Data_column VARCHAR(10) NOT NULL );
INSERT INTO table3(ID,Data_column) VALUES ('1528','t3somedata'), ('9523','t3somedata');
我已经使用了这个splistring函数,但是您可以使用几乎所有免费版本中的任何一个。
CREATE FUNCTION dbo.SplitStrings_Moden ( @List NVARCHAR(MAX), @Delimiter NVARCHAR(255) ) 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), E42(N) AS (SELECT 1 FROM E4 a, E2 b), cteTally(N) AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42), cteStart(N1) AS (SELECT t.N+1 FROM cteTally t WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0)) SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000)) FROM cteStart s;
使用splitstring函数,数据看起来像这样:
select * from table1 cross apply SplitStrings_Moden(reference_number,',')
ID | Data_column | reference_number | Item -: | :---------- | :--------------- | :----- 1 | t1somedata | 1528,ss-456 | 1528 1 | t1somedata | 1528,ss-456 | ss-456 2 | t1somedata | 9523 | 9523 3 | t1somedata | ss-952 | ss-952 4 | t1somedata | null | null
现在加入其他表:
select * from ( select * from table1 cross apply SplitStrings_Moden(reference_number,',') ) t1 left join table2 on t1.item = table2.id left join table3 on t1.item = table3.id where t1.item is not null GO
ID | Data_column | reference_number | Item | ID | Data_column | ID | Data_column -: | :---------- | :--------------- | :----- | :----- | :---------- | :--- | :---------- 1 | t1somedata | 1528,ss-456 | 1528 | null | null | 1528 | t3somedata 1 | t1somedata | 1528,ss-456 | ss-456 | ss-456 | t2somedata | null | null 2 | t1somedata | 9523 | 9523 | null | null | 9523 | t3somedata 3 | t1somedata | ss-952 | ss-952 | ss-952 | t2somedata | null | null
db <>提琴here
答案 4 :(得分:0)
请尝试:如果您的reference_number
是固定的,并且始终只能存储最多2个ID,那么您可以采用以下方法
SELECT *
FROM(
SELECT ID,
data_column,
CASE WHEN PATINDEX ( '%,%', reference_number) > 0 THEN
SUBSTRING(reference_number, PATINDEX ( '%,%', reference_number)+1, LEN(reference_number))
ELSE reference_number END AS ref_col
FROM @table1
UNION
SELECT ID,
data_column,
CASE WHEN PATINDEX ( '%,%', reference_number) > 0 THEN
SUBSTRING(reference_number, 0, PATINDEX ( '%,%', reference_number))
END
FROM @table1) t1
LEFT JOIN @table2 t2 ON t2.id = t1.ref_col
LEFT JOIN @table3 t3 ON t3.id = t1.ref_col
WHERE t1.ref_col IS NOT NULL
输出:
ID data_column ref_col ID Data_column ID Data_column
1 some data 1528 NULL NULL 1528 some data
1 some data ss-456 ss-456 some data NULL NULL
2 some data 9523 NULL NULL 9523 some data
3 some data ss-952 ss-952 some data NULL NULL
4 some data null NULL NULL NULL NULL
答案 5 :(得分:0)
您可以使用Substring
上的charIndex
和reference_number
函数来实现并获得期望的结果。
我赞成使用“ is_oz”作为答案,因为我使用了现成的架构来为您测试和建立查询。
以下是我在several tries i made here之后建立的最终查询:
select * from abc
left join abc2 on abc2.id = case when charindex(',',abc.reference_number) > 0
then substring(abc.reference_number
,charindex(',',abc.reference_number)+1
,len(abc.reference_number)-(charindex(',',abc.reference_number)-1)
)
else abc.reference_number
end
left join abc3 on abc3.id = case when charindex(',',abc.reference_number) > 0
then substring(abc.reference_number
,0
,(charindex(',',abc.reference_number))
)
else abc.reference_number
end
据我所知,根据您的要求,它正在从其他2个表中返回所有匹配的行,但是我仍然希望这能够满足您在问题中寻求的所有要求。 :)