Объединение таблиц, содержащих значения, разделенные запятыми - PullRequest
0 голосов
/ 03 октября 2018

У меня есть три листа Excel, я помещаю их в таблицы на SQL-сервере, и мне нужно присоединиться к этим таблицам.Тем не менее, я считаю - как я уже пытался - нормальное объединение не будет работатьУ меня есть опыт программирования, но не так много с 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

В случае ниже Как я смогу присоединиться к этому raw в обеих таблицах.

Table1

ID  Data_column reference_number
1   some data   1528,ss-456

Ответы [ 6 ]

0 голосов
/ 03 октября 2018

Вы можете реализовать и получить желаемый результат, используя функции Substring и charIndex на reference_number.

Я проголосовал за ответ is_oz, так как использовал его готовую схему для тестирования и сборкизапрос для вас.

ниже - это последний запрос, который я построил после нескольких попыток, которые я сделал здесь :

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 других таблиц, но все же я надеюсь, что это удовлетворяет всем требованиям, которые вы ищете в своем вопросе.:)

0 голосов
/ 03 октября 2018

ПОПРОБУЙТЕ ЭТО: Если ваш reference_number является фиксированным и всегда хранит идентификаторы до 2 только тогда, вы можете использовать следующий подход

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    
0 голосов
/ 03 октября 2018
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

Вы можете изменить «левое внешнее соединение» на «внутреннее соединение» для точного соответствия.

0 голосов
/ 03 октября 2018

Неуклюжий дизайн, неуклюжее решение:

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%.

0 голосов
/ 03 октября 2018

Вам потребуется функция для разделения строки, разделенной запятыми, на строки.Если у вас нет доступа к встроенной функции string_split () (по состоянию на mssql 2017 с совместимостью 130), есть несколько вариантов на выбор здесь

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  | <em>null</em>             | <em>null</em>  

и теперь присоединяются кдругие таблицы:

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   | <em>null</em>   | <em>null</em>        | 1528 | t3somedata 
 1 | t1somedata  | 1528,ss-456      | ss-456 | ss-456 | t2somedata  | <em>null</em> | <em>null</em>       
 2 | t1somedata  | 9523             | 9523   | <em>null</em>   | <em>null</em>        | 9523 | t3somedata 
 3 | t1somedata  | ss-952           | ss-952 | ss-952 | t2somedata  | <em>null</em> | <em>null</em>       

db <> скрипка здесь

0 голосов
/ 03 октября 2018

Я вижу две проблемы здесь.Во-первых, это несовместимый тип идентификатора в таблицах 2 и 3 и агрегация ссылочных ключей в таблице 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...