Выбор данных по числовым значениям, сохраненным в виде строки, разделенной запятыми - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть две таблицы sql, и я ищу запрос sql, чтобы выбрать данные для каждого числового значения в столбце Table1.ValueID из столбца Table2.ValueDescription и сохранить результат в Table3

Table1:

ID  ValueID
1   1,12,14
2   3,5,15
3   2,6,13,16

Table2:

ValueID   ValueDescription
1         Motor
2         Low
3         Failed
4         New Install
5         New Item
6         Max Value
7         AC Current
8         DC Current
9         Not Reached
10        NA
11        Cutoff
12        Manual
13        Automatic
14        Device Not Found
15        Halt
16        Renew

Ожидаемый результат:

Table3:

ID  ValueID       Result
1   1,12,14       Motor,Manual,Device Not Found
2   3,5,15        Failed,New Item,Halt
3   2,6,13,16     Low,Max Value,Automatic,Renew

Использование SQL Server Management Studio

Вот запрос Iпробовал

 SELECT Table1.ValueID,
   Stuff((SELECT ',' + CAST(Table2.Description AS VARCHAR(100))
           FROM Table2
          WHERE Table1.ValueID LIKE Table2.ValueID
            FOR Xml Path('')),1,1,'')
FROM Table1

что мне здесь не хватает?

Ответы [ 4 ]

0 голосов
/ 30 ноября 2018

Это не намного красивее, но новые встроенные функции в SQL Server 2017 делают это немного проще, и все же можно сделать так, чтобы он соответствовал порядку исходного списка (ну, я даже не могу сказать,если вы намеревались сделать заказ по местоположению в списке или по числовому порядку (поскольку они одинаковы), то при условии, что это все целые числа и нет дубликатов:

;WITH explode(ID, ValueID, value, i) AS
(
  SELECT t1.ID,  
    t1.ValueID,
    TRY_CONVERT(int,f.value), 
    CHARINDEX(',' + f.value + ',', ',' + t1.ValueID + ',')
  FROM dbo.Table1 t1
  CROSS APPLY STRING_SPLIT(t1.ValueID, ',') AS f
)
SELECT x.ID, x.ValueID, 
  -- guarantee respect original order:
  Result = STRING_AGG(t2.ValueDescription,',') WITHIN GROUP (ORDER BY x.i)
FROM explode AS x
INNER JOIN dbo.Table2 AS t2
ON x.value = t2.ValueID
GROUP BY x.ID, x.ValueID
ORDER BY x.ID;

Если порядок не имеет значения,и вы уверены, что в списке ValueID в Table1 не может быть дубликатов или нецелых чисел, это гораздо проще:

;WITH explode(ID, ValueID, value) AS
(
  SELECT t1.ID, t1.ValueID, f.value
  FROM dbo.Table1 t1
  CROSS APPLY STRING_SPLIT(t1.ValueID, ',') AS f
)
SELECT x.ID, x.ValueID, STRING_AGG(t2.ValueDescription,',')
FROM explode AS x
INNER JOIN dbo.Table2 AS t2
ON x.value = t2.ValueID
GROUP BY x.ID, x.ValueID
ORDER BY x.ID;
0 голосов
/ 30 ноября 2018

Если вы действительно используете SQL Server 2017, вы можете использовать функции STRING_SPLIT и STRING_AGG.Они обеспечивают очень простой синтаксис.

IF OBJECT_ID('tempdb..#Table1', 'U') IS NOT NULL 
DROP TABLE #Table1;

CREATE TABLE #Table1 (
    ID INT NOT NULL PRIMARY KEY,
    ValueID VARCHAR(50) NOT NULL 
    );
INSERT #Table1 (ID, ValueID) VALUES
    (1, '1,12,14'),
    (2, '3,5,15'),
    (3, '2,6,13,16');

IF OBJECT_ID('tempdb..#Table2', 'U') IS NOT NULL 
DROP TABLE #Table2;

CREATE TABLE #Table2 (
    ValueID INT NOT NULL PRIMARY KEY,
    ValueDescription VARCHAR(50) NOT NULL 
    );
INSERT #Table2(ValueID, ValueDescription) VALUES
    (1, 'Motor'),
    (2, 'Low'),
    (3, 'Failed'),
    (4, 'New Install'),
    (5, 'New Item'),
    (6, 'Max Value'),
    (7, 'AC Current'),
    (8, 'DC Current'),
    (9, 'Not Reached'),
    (10, 'NA'),
    (11, 'Cutoff'),
    (12, 'Manual'),
    (13, 'Automatic'),
    (14, 'Device Not Found'),
    (15, 'Halt'),
    (16, 'Renew');

--SELECT * FROM #Table1 t1;
--SELECT * FROM #Table2 t2;

--========================================================

SELECT 
    t1.ID,
    t1.ValueID,
    csv.Result
FROM
    #Table1 t1
    CROSS APPLY (
            SELECT 
                Result = STRING_AGG(t2.ValueDescription, ',')
            FROM
                STRING_SPLIT(t1.ValueID, ',') ss
                JOIN #Table2 t2
                    ON CONVERT(INT, ss.value) = t2.ValueID
            ) csv;

Результаты ...

ID          ValueID        Result
----------- -------------- -----------------------------------
1           1,12,14        Motor,Manual,Device Not Found
2           3,5,15         Failed,New Item,Halt
3           2,6,13,16      Low,Max Value,Automatic,Renew

Редактировать:

-

-============================================================================
-- This is an idea that I've been kicking around for a little while now. 
-- It's based on the SUSPICION that, when left to it's own devices. STRING_SPLIT
-- will always retun rows in the original order and attaching a row_number() 
-- to the output, right out of the gate, will effectively serve as an "ItemNumber.
--============================================================================

SELECT 
    t1.ID,
    t1.ValueID,
    csv.Result
FROM
    #Table1 t1
    CROSS APPLY (
            SELECT 
                Result = STRING_AGG(t2.ValueDescription, ',') WITHIN GROUP (ORDER BY rs.rn DESC) -- sort in the descending order for no real eason...
            FROM (
                    SELECT 
                        rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)),
                        ValueID = CONVERT(INT, ss.value)
                    FROM 
                        STRING_SPLIT(t1.ValueID, ',') ss
                    ) rs
                JOIN #Table2 t2
                    ON rs.ValueID = t2.ValueID
            ) csv;

ID          ValueID       Result
----------- ------------- --------------------------------
1           1,12,14       Device Not Found,Manual,Motor
2           3,5,15        Halt,New Item,Failed
3           2,6,13,16     Renew,Automatic,Max Value,Low
0 голосов
/ 30 ноября 2018

Вы можете сделать как

SELECT *,
       STUFF(
         (
           SELECT ',' + ValueDescription
           FROM T2
           WHERE ',' + T1.ValueID + ',' LIKE '%,' + CAST(T2.ValueID AS VARCHAR) + ',%'
           FOR XML PATH('')
         ),
         1, 1, ''
       ) ValueDescription
FROM T1;

Возвраты:

+----+-----------+-------------------------------+
| ID |  ValueID  |       ValueDescription        |
+----+-----------+-------------------------------+
|  1 |   1,12,14 | Motor,Manual,Device Not Found |
|  2 |    3,5,15 | Failed,New Item,Halt          |
|  3 | 2,6,13,16 | Low,Max Value,Automatic,Renew |
+----+-----------+-------------------------------+

Демо

0 голосов
/ 30 ноября 2018

Это сохранит правильную последовательность

Пример

Select A.* 
      ,B.*
 From  Table1 A
 Cross Apply (
                Select Result = Stuff((Select ',' +B2.ValueDescription 
                  From (
                        Select RetSeq = Row_Number() over (Order By (Select null))
                              ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace(A.ValueID,',','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B1
                  Join  Table2 B2 on B1.RetVal=B2.ValueID
                  Order by RetSeq
                  For XML Path ('')),1,1,'') 
             ) B

Возвращает

ID  ValueID     Result
1   1,12,14     Motor,Manual,Device Not Found
2   3,5,15      Failed,New Item,Halt
3   2,6,13,16   Low,Max Value,Automatic,Renew

Упс - Только что увидел, что вы 2017

...