Можно ли использовать STRING_SPLIT в предложении ORDER BY? - PullRequest
0 голосов
/ 10 апреля 2020

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

Я думал, что смогу выполнить sh с помощью функции string_split, но я не очень опытен с SQL и поэтому я сталкиваюсь с некоторыми проблемами.

Вот что у меня есть:

UPDATE lse
SET Options = a.Options
FROM
    dbo.LessonStepElement as lse
CROSS JOIN
(
    SELECT
        tbl1.*
        tbl2.Options,
        tbl2.QuestionId
    FROM
        dbo.TrainingQuestionAnswer as tbl1
    JOIN (
        SELECT
            string_agg((CASE
                        WHEN tqa.CorrectAnswer = 1 THEN REPLACE(tqa.AnswerText, tqa.AnswerText, '*' + tqa.AnswerText)
                        ELSE tqa.AnswerText
                        END),
                        char(10)) as Options,
            tq.Id as QuestionId
        FROM
            dbo.TrainingQuestionAnswer as tqa
        INNER JOIN
            dbo.TrainingQuestion as tq
            on tq.Id = tqa.TrainingQuestionId
        INNER JOIN
            dbo.Training as t
            on t.Id = tq.TrainingId        
        WHERE 
            t.IsDeleted = 0
        and tq.IsDeleted = 0
        and tqa.IsDeleted = 0
        GROUP BY
            tq.Id,
            tqa.AnswerDisplayOrder    
        ORDER BY
            (SELECT [Value] FROM STRING_SPLIT((SELECT AnswerDisplayOrder FROM dbo.TrainingQuestion WHERE Id = tmq.Id), ','))
        ) as tbl2
    on tbl1.TrainingQuestionId = tbl2.QuestionId
) a
WHERE
    a.TrainingQuestionId = lse.TrainingQuestionId

Я использую AnswerDisplayOrder - это просто nvarchar список, разделенный запятыми id s для ответов на вопрос.

Вот пример:

У меня есть 3 строки в таблице TrainingQuestionAnswer, которые выглядят следующим образом.

ID      TrainingQuestionId      AnswerText
-------------------------------------------
215     100                     No
218     100                     Yes
220     100                     I'm not sure

У меня есть 1 строка в таблице TrainingQuestion, которая выглядит следующим образом.

ID      AnswerDisplayOrder
--------------------------
100     "218,215,220"

Теперь я пытаюсь сделать следующее: обновить строку в новой таблице, объединяя все ответы, ответы должен быть в правильном порядке, который зависит от AnswerDisplayOrder в таблице TrainingQuestion. По сути, в новой таблице будет строка, похожая на следующую:

ID     Options
--------------
193    "Yes No I'm not sure"

Я знаю, что способ, которым я пытаюсь это сделать, может вообще не быть возможным. Я все еще учусь и просто хотел бы получить несколько советов или рекомендаций о том, как сделать эту работу. Я также знаю, что string_split не гарантирует порядок. Я открыт для других предложений, которые также гарантируют заказ.

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

Я упростил проблему в вопросе до следующего подхода, который является возможным решением вашей проблемы. Если вы хотите получить результаты из вопроса, вам нужен разделитель, который возвращает подстроки и позиции подстрок. STRING_SPLIT() доступен с SQL Server 2016, но здесь не вариант, потому что (как указано в документации ) выходные строки могут быть в любом порядке и порядок не гарантированно совпадает с порядком подстрок во входной строке .

Но вы можете попробовать использовать подход на основе JSON с небольшой обработкой строк, который преобразует ответы Идентификаторы в действительный массив JSON (218,215,220 в [218,215,220]). После этого вы можете легко разобрать этот массив JSON с OPENJSON() и схемой по умолчанию. В результате получается таблица со столбцами key, value и type, а столбец key (снова из документации ) содержит индекс элемента в указанном массиве .

Таблицы:

CREATE TABLE TrainingQuestionId (
   ID int,
   TrainingQuestionId int,
   AnswerText varchar(1000)
)
INSERT INTO TrainingQuestionId 
   (ID, TrainingQuestionId, AnswerText)
VALUES   
   (215, 100, 'No'),
   (218, 100, 'Yes'),
   (220, 100, 'I''m not sure')
CREATE TABLE TrainingQuestion (   
  ID int,
  AnswerDisplayOrder varchar(1000)
)
INSERT INTO TrainingQuestion
   (ID, AnswerDisplayOrder)
VALUES
   (100, '218,215,220')

Заявление:

SELECT tq.ID, oa.Options
FROM TrainingQuestion tq
OUTER APPLY ( 
   SELECT STRING_AGG(tqi.AnswerText, ' ') WITHIN GROUP (ORDER BY CONVERT(int, j.[key])) AS Options
   FROM OPENJSON(CONCAT('[', tq.AnswerDisplayOrder, ']')) j
   LEFT JOIN TrainingQuestionId tqi ON TRY_CONVERT(int, j.[value]) = tqi.ID 
) oa

Результат:

ID  Options
100 Yes No I'm not sure

Примечания: Вам нужно SQL Сервер 2017+ использовать STRING_AGG(). Для SQL Server 2016 вам нужно FOR XML для объединения строк.

0 голосов
/ 11 апреля 2020
declare @TrainingQuestionAnswer table
(
ID int,
TrainingQuestionId int,
AnswerText varchar(20)
);

insert into @TrainingQuestionAnswer(ID, TrainingQuestionId, AnswerText)
values(215, 100, 'No'), (218, 100, 'Yes'), (220, 100, 'I''m not sure');

declare @TrainingQuestiontest table
(
testid int identity,
QuestionId int,
AnswerDisplayOrder varchar(200)
);

insert into @TrainingQuestiontest(QuestionId, AnswerDisplayOrder)
values(100, '218,215,220'), (100, '220,218,215'), (100, '215,218');

select *, 
(
   select string_agg(pci.AnswerText, '==') WITHIN GROUP ( ORDER BY pci.pos)
   from
   (
    select a.AnswerText,
         pos = charindex(concat(',', a.ID, ','), concat(',', q.AnswerDisplayOrder,','))
    from @TrainingQuestionAnswer as a
    where a.TrainingQuestionId = q.QuestionId
    and charindex(concat(',', a.ID, ','), concat(',', q.AnswerDisplayOrder,',')) >= 1
   ) as pci
) as TestAnswerText
from @TrainingQuestiontest as q;
...